yamchart 0.8.8 → 0.9.0

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 (65) hide show
  1. package/dist/{advisor-IJBW56F5.js → advisor-Z7TKPPBR.js} +10 -10
  2. package/dist/{agent-2DFNL2UB.js → agent-KWKPAYT2.js} +2 -2
  3. package/dist/{chunk-34ZVFILD.js → chunk-AMHCOB4D.js} +4 -4
  4. package/dist/{chunk-5N3FYFBV.js → chunk-CWAWATL4.js} +34 -7
  5. package/dist/chunk-CWAWATL4.js.map +1 -0
  6. package/dist/{chunk-D3ELUYYE.js → chunk-E2QN2M7S.js} +52 -5
  7. package/dist/chunk-E2QN2M7S.js.map +1 -0
  8. package/dist/{chunk-B5ZLCKNF.js → chunk-FZFBBB7K.js} +2 -2
  9. package/dist/{chunk-232AMQ5T.js → chunk-G57J2WQM.js} +4 -4
  10. package/dist/{chunk-77U26A7F.js → chunk-ZA6AOQVZ.js} +4 -4
  11. package/dist/chunk-ZA6AOQVZ.js.map +1 -0
  12. package/dist/{connection-utils-ZLSV5OLQ.js → connection-utils-CTPN7PV3.js} +4 -4
  13. package/dist/{describe-VO4CEYL2.js → describe-4NME6RCB.js} +5 -5
  14. package/dist/{dev-JUA73B6D.js → dev-6QGAB4ZH.js} +316 -29
  15. package/dist/dev-6QGAB4ZH.js.map +1 -0
  16. package/dist/{dist-PINRLZVT.js → dist-4GUE24QV.js} +2 -2
  17. package/dist/{dist-GVNWQXFR.js → dist-7CRX2GIR.js} +2 -2
  18. package/dist/{dist-E2PVGIPT.js → dist-VNX77VV5.js} +4 -2
  19. package/dist/index.js +21 -21
  20. package/dist/public/assets/{EventManagement-DQY1Sic0.js → EventManagement-MMsAkJKj.js} +2 -2
  21. package/dist/public/assets/{ExplorePage-C9M-fQ3Y.js → ExplorePage-BSkSNgLT.js} +1 -1
  22. package/dist/public/assets/{LoginPage-XYLwfbfw.js → LoginPage-vaI1dnyL.js} +1 -1
  23. package/dist/public/assets/PublicViewer-B-OKj2cg.js +1 -0
  24. package/dist/public/assets/{SetupWizard-fle7FC4b.js → SetupWizard-DvlVX2O6.js} +1 -1
  25. package/dist/public/assets/{ShareManagement-b3j4jzn3.js → ShareManagement-ulvPrOAQ.js} +1 -1
  26. package/dist/public/assets/{UserManagement-DwZ-AaqI.js → UserManagement-CvmpNy3o.js} +1 -1
  27. package/dist/public/assets/{index-CRcgti3B.css → index-CfyF2Wf-.css} +1 -1
  28. package/dist/public/assets/index-DD59fsOk.js +195 -0
  29. package/dist/public/assets/{index.es-Bd2YVqtj.js → index.es-BeTaRWIv.js} +1 -1
  30. package/dist/public/assets/{jspdf.es.min-CpRfbJ_H.js → jspdf.es.min-9haD1GSE.js} +3 -3
  31. package/dist/public/index.html +2 -2
  32. package/dist/{query-PXJMSDKR.js → query-Z75RKTHV.js} +4 -4
  33. package/dist/{sample-M24H3M73.js → sample-OIJNXQNC.js} +4 -4
  34. package/dist/{search-UCJS7X5D.js → search-YDCPIDZX.js} +5 -5
  35. package/dist/{source-resolver-RXNB7A64.js → source-resolver-4SUWXUGW.js} +5 -5
  36. package/dist/{sync-warehouse-S75DWVTG.js → sync-warehouse-NZFDS6WK.js} +4 -4
  37. package/dist/{tables-W3M3JDJO.js → tables-WJS2VI4L.js} +5 -5
  38. package/dist/templates/default/CLAUDE.md +1 -1
  39. package/dist/templates/default/docs/yamchart-reference.md +108 -2
  40. package/dist/{test-67AXD5PI.js → test-I4XOF7TZ.js} +5 -17
  41. package/dist/test-I4XOF7TZ.js.map +1 -0
  42. package/package.json +3 -3
  43. package/dist/chunk-5N3FYFBV.js.map +0 -1
  44. package/dist/chunk-77U26A7F.js.map +0 -1
  45. package/dist/chunk-D3ELUYYE.js.map +0 -1
  46. package/dist/dev-JUA73B6D.js.map +0 -1
  47. package/dist/public/assets/PublicViewer-CZJYS0wF.js +0 -1
  48. package/dist/public/assets/index-m_Jm3sB1.js +0 -188
  49. package/dist/test-67AXD5PI.js.map +0 -1
  50. /package/dist/{advisor-IJBW56F5.js.map → advisor-Z7TKPPBR.js.map} +0 -0
  51. /package/dist/{agent-2DFNL2UB.js.map → agent-KWKPAYT2.js.map} +0 -0
  52. /package/dist/{chunk-34ZVFILD.js.map → chunk-AMHCOB4D.js.map} +0 -0
  53. /package/dist/{chunk-B5ZLCKNF.js.map → chunk-FZFBBB7K.js.map} +0 -0
  54. /package/dist/{chunk-232AMQ5T.js.map → chunk-G57J2WQM.js.map} +0 -0
  55. /package/dist/{connection-utils-ZLSV5OLQ.js.map → connection-utils-CTPN7PV3.js.map} +0 -0
  56. /package/dist/{describe-VO4CEYL2.js.map → describe-4NME6RCB.js.map} +0 -0
  57. /package/dist/{dist-E2PVGIPT.js.map → dist-4GUE24QV.js.map} +0 -0
  58. /package/dist/{dist-GVNWQXFR.js.map → dist-7CRX2GIR.js.map} +0 -0
  59. /package/dist/{dist-PINRLZVT.js.map → dist-VNX77VV5.js.map} +0 -0
  60. /package/dist/{query-PXJMSDKR.js.map → query-Z75RKTHV.js.map} +0 -0
  61. /package/dist/{sample-M24H3M73.js.map → sample-OIJNXQNC.js.map} +0 -0
  62. /package/dist/{search-UCJS7X5D.js.map → search-YDCPIDZX.js.map} +0 -0
  63. /package/dist/{source-resolver-RXNB7A64.js.map → source-resolver-4SUWXUGW.js.map} +0 -0
  64. /package/dist/{sync-warehouse-S75DWVTG.js.map → sync-warehouse-NZFDS6WK.js.map} +0 -0
  65. /package/dist/{tables-W3M3JDJO.js.map → tables-WJS2VI4L.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  loadEnvFile,
3
3
  validateProject
4
- } from "./chunk-232AMQ5T.js";
4
+ } from "./chunk-G57J2WQM.js";
5
5
  import {
6
6
  box,
7
7
  detail,
@@ -23,11 +23,11 @@ import {
23
23
  SemanticQuerySchema,
24
24
  deepMerge,
25
25
  resolveProjectConfig
26
- } from "./chunk-D3ELUYYE.js";
26
+ } from "./chunk-E2QN2M7S.js";
27
27
  import {
28
28
  StreamingChatAgent,
29
29
  filterCatalogEntries
30
- } from "./chunk-77U26A7F.js";
30
+ } from "./chunk-ZA6AOQVZ.js";
31
31
  import {
32
32
  AuthDatabase,
33
33
  generateSessionToken,
@@ -57,7 +57,7 @@ import {
57
57
  resolveMySQLAuth,
58
58
  resolvePostgresAuth,
59
59
  resolveSnowflakeAuth
60
- } from "./chunk-5N3FYFBV.js";
60
+ } from "./chunk-CWAWATL4.js";
61
61
  import {
62
62
  SemanticModelBuilder,
63
63
  SemanticQueryCompiler,
@@ -804,12 +804,18 @@ function parseTtl2(ttl) {
804
804
  }
805
805
 
806
806
  // ../server/dist/services/query-service.js
807
+ function quoteIdentifier(name, dialect) {
808
+ if (dialect === "mysql")
809
+ return `\`${name.replace(/`/g, "``")}\``;
810
+ return `"${name.replace(/"/g, '""')}"`;
811
+ }
807
812
  var QueryService = class {
808
813
  compiler;
809
814
  connector;
810
815
  cache;
811
816
  models;
812
817
  refs;
818
+ dialect;
813
819
  constructor(config) {
814
820
  this.compiler = new QueryCompiler({
815
821
  models: config.models,
@@ -819,6 +825,7 @@ var QueryService = class {
819
825
  this.cache = config.cache;
820
826
  this.models = new Map(Object.entries(config.models));
821
827
  this.refs = config.refs;
828
+ this.dialect = config.dialect ?? "duckdb";
822
829
  }
823
830
  async executeChart(chart, params, userContext) {
824
831
  const compiled = this.compiler.compile(chart, params, userContext);
@@ -850,6 +857,120 @@ var QueryService = class {
850
857
  compiledSql: compiled.sql
851
858
  };
852
859
  }
860
+ /**
861
+ * Execute a table chart with server-side pagination.
862
+ * Wraps the compiled SQL with LIMIT/OFFSET and runs a parallel COUNT(*) query.
863
+ * Optionally computes summary aggregations for specified columns.
864
+ */
865
+ async executeChartPaginated(chart, params, options, userContext) {
866
+ const compiled = this.compiler.compile(chart, params, userContext);
867
+ const baseSql = compiled.sql;
868
+ const q = quoteIdentifier;
869
+ const d = this.dialect;
870
+ let orderBy = "";
871
+ if (options.sortField) {
872
+ const cleanField = options.sortField.replace(/[^\w\s]/g, "");
873
+ if (cleanField.length > 0) {
874
+ orderBy = `ORDER BY ${q(cleanField, d)} ${options.sortDirection === "desc" ? "DESC" : "ASC"}`;
875
+ }
876
+ }
877
+ const offset = options.page * options.pageSize;
878
+ const dataSql = `SELECT * FROM (${baseSql}) _t ${orderBy} LIMIT ${options.pageSize} OFFSET ${offset}`;
879
+ const countCacheKey = `${compiled.cacheKey}:count`;
880
+ let totalCount;
881
+ const cachedCount = await this.cache.get(countCacheKey);
882
+ if (cachedCount) {
883
+ totalCount = cachedCount.rowCount;
884
+ } else {
885
+ const countSql = `SELECT COUNT(*) AS _count FROM (${baseSql}) _t`;
886
+ const countResult = await this.connector.execute(countSql);
887
+ totalCount = Number(countResult.rows[0]?._count ?? 0);
888
+ await this.cache.set(countCacheKey, {
889
+ columns: [],
890
+ rows: [],
891
+ rowCount: totalCount,
892
+ durationMs: countResult.durationMs,
893
+ cachedAt: Date.now()
894
+ });
895
+ }
896
+ let summaryValues;
897
+ if (options.summaryColumns && options.summaryColumns.length > 0) {
898
+ const summaryCacheKey = `${compiled.cacheKey}:summary`;
899
+ const cachedSummary = await this.cache.get(summaryCacheKey);
900
+ if (cachedSummary && cachedSummary.rows[0]) {
901
+ summaryValues = cachedSummary.rows[0];
902
+ } else {
903
+ const aggExprs = options.summaryColumns.map(({ field, summary }) => {
904
+ const col = q(field, d);
905
+ switch (summary) {
906
+ case "sum":
907
+ return `SUM(${col}) AS ${q(`_sum_${field}`, d)}`;
908
+ case "avg":
909
+ return `AVG(${col}) AS ${q(`_avg_${field}`, d)}`;
910
+ case "min":
911
+ return `MIN(${col}) AS ${q(`_min_${field}`, d)}`;
912
+ case "max":
913
+ return `MAX(${col}) AS ${q(`_max_${field}`, d)}`;
914
+ case "count":
915
+ return `COUNT(${col}) AS ${q(`_count_${field}`, d)}`;
916
+ default:
917
+ return null;
918
+ }
919
+ }).filter(Boolean);
920
+ if (aggExprs.length > 0) {
921
+ const summarySql = `SELECT ${aggExprs.join(", ")} FROM (${baseSql}) _t`;
922
+ const summaryResult = await this.connector.execute(summarySql);
923
+ if (summaryResult.rows[0]) {
924
+ summaryValues = {};
925
+ for (const { field, summary } of options.summaryColumns) {
926
+ const key = `_${summary}_${field}`;
927
+ summaryValues[`${summary}:${field}`] = Number(summaryResult.rows[0][key] ?? 0);
928
+ }
929
+ await this.cache.set(summaryCacheKey, {
930
+ columns: [],
931
+ rows: [summaryValues],
932
+ rowCount: 0,
933
+ durationMs: summaryResult.durationMs,
934
+ cachedAt: Date.now()
935
+ });
936
+ }
937
+ }
938
+ }
939
+ }
940
+ const result = await this.connector.execute(dataSql);
941
+ return {
942
+ ...result,
943
+ cached: false,
944
+ cacheKey: compiled.cacheKey,
945
+ compiledSql: dataSql,
946
+ totalCount,
947
+ page: options.page,
948
+ pageSize: options.pageSize,
949
+ summaryValues
950
+ };
951
+ }
952
+ /**
953
+ * Execute a chart query for CSV export with a bounded row limit.
954
+ * Returns full QueryResult — caller streams to HTTP response.
955
+ */
956
+ async executeChartForExport(chart, params, maxRows, userContext) {
957
+ const compiled = this.compiler.compile(chart, params, userContext);
958
+ const sql = `SELECT * FROM (${compiled.sql}) _t LIMIT ${maxRows}`;
959
+ const result = await this.connector.execute(sql);
960
+ return {
961
+ ...result,
962
+ cached: false,
963
+ cacheKey: compiled.cacheKey,
964
+ compiledSql: sql
965
+ };
966
+ }
967
+ /**
968
+ * Compile a chart query without executing it.
969
+ * Returns the compiled SQL and cache key.
970
+ */
971
+ compileChart(chart, params, userContext) {
972
+ return this.compiler.compile(chart, params, userContext);
973
+ }
853
974
  invalidateChart(chartName) {
854
975
  this.cache.invalidatePattern(`${chartName}:*`);
855
976
  }
@@ -1132,6 +1253,12 @@ function classifyError(error2) {
1132
1253
  }
1133
1254
  return "query_error";
1134
1255
  }
1256
+ function escapeCSVField(value) {
1257
+ if (value.includes(",") || value.includes('"') || value.includes("\n") || value.includes("\r")) {
1258
+ return `"${value.replace(/"/g, '""')}"`;
1259
+ }
1260
+ return value;
1261
+ }
1135
1262
  function getUserContext(request) {
1136
1263
  const user = request.user;
1137
1264
  if (!user)
@@ -1196,15 +1323,78 @@ async function chartRoutes(fastify, options) {
1196
1323
  });
1197
1324
  fastify.post("/api/charts/:name/query", async (request, reply) => {
1198
1325
  const { name } = request.params;
1199
- const params = request.body ?? {};
1326
+ const rawParams = request.body ?? {};
1200
1327
  const includeConfig = request.query.includeConfig === "true";
1201
1328
  const chart = configLoader.getChartByName(name);
1202
1329
  if (!chart) {
1203
1330
  const resp = chartNotFoundResponse(configLoader, name);
1204
1331
  return reply.status(resp.status).send(resp.body);
1205
1332
  }
1333
+ const { _page, _page_size, _sort_field, _sort_dir, _server_paginated, ...params } = rawParams;
1206
1334
  try {
1207
- const result = await queryService.executeChart(chart, params, getUserContext(request));
1335
+ const isTable = chart.chart?.type === "table";
1336
+ const project = configLoader.getProject();
1337
+ const chartMaxRows = chart.chart?.max_rows;
1338
+ const maxDisplayRows = chartMaxRows ?? project?.defaults?.table?.max_display_rows ?? 1e4;
1339
+ const forceServerSide = chart.chart?.pagination && chart.chart.pagination?.server_side === true;
1340
+ if (isTable && _server_paginated) {
1341
+ const page = Number(_page) || 0;
1342
+ const pageSize = Number(_page_size) || 50;
1343
+ const columns = chart.chart?.columns ?? [];
1344
+ const summaryColumns = columns.filter((c) => c.summary).map((c) => ({ field: c.field, summary: c.summary }));
1345
+ const paginatedResult = await queryService.executeChartPaginated(chart, params, { page, pageSize, sortField: _sort_field, sortDirection: _sort_dir, summaryColumns }, getUserContext(request));
1346
+ reply.header("X-Cache", "MISS");
1347
+ reply.header("X-Query-Duration-Ms", paginatedResult.durationMs.toFixed(0));
1348
+ const response2 = {
1349
+ columns: paginatedResult.columns,
1350
+ rows: paginatedResult.rows,
1351
+ meta: {
1352
+ cached: paginatedResult.cached,
1353
+ durationMs: paginatedResult.durationMs,
1354
+ rowCount: paginatedResult.rowCount,
1355
+ cacheKey: paginatedResult.cacheKey,
1356
+ compiledSql: paginatedResult.compiledSql,
1357
+ serverPaginated: true,
1358
+ totalCount: paginatedResult.totalCount,
1359
+ page,
1360
+ pageSize
1361
+ },
1362
+ ...paginatedResult.summaryValues ? { summaryValues: paginatedResult.summaryValues } : {}
1363
+ };
1364
+ if (includeConfig) {
1365
+ response2.config = {
1366
+ name: chart.name,
1367
+ title: chart.title,
1368
+ description: chart.description,
1369
+ parameters: chart.parameters ?? [],
1370
+ chart: chart.chart,
1371
+ drillDown: chart.drillDown
1372
+ };
1373
+ }
1374
+ return response2;
1375
+ }
1376
+ let result;
1377
+ let serverPaginated = false;
1378
+ let totalCount;
1379
+ if (isTable) {
1380
+ const probeResult = await queryService.executeChartForExport(chart, params, maxDisplayRows + 1, getUserContext(request));
1381
+ if (probeResult.rowCount > maxDisplayRows || forceServerSide) {
1382
+ serverPaginated = true;
1383
+ if (probeResult.rowCount > maxDisplayRows) {
1384
+ const compiled = queryService.compileChart(chart, params, getUserContext(request));
1385
+ const countResult = await queryService.executeRawSql(`SELECT COUNT(*) AS _count FROM (${compiled.sql}) _t`);
1386
+ totalCount = Number(countResult.rows[0]?._count ?? 0);
1387
+ result = { ...probeResult, rows: probeResult.rows.slice(0, maxDisplayRows), rowCount: maxDisplayRows };
1388
+ } else {
1389
+ totalCount = probeResult.rowCount;
1390
+ result = probeResult;
1391
+ }
1392
+ } else {
1393
+ result = probeResult;
1394
+ }
1395
+ } else {
1396
+ result = await queryService.executeChart(chart, params, getUserContext(request));
1397
+ }
1208
1398
  let comparison = void 0;
1209
1399
  if (chart.chart?.type === "kpi" && chart.chart?.comparison?.period === "previous") {
1210
1400
  let startDate = params.start_date;
@@ -1247,6 +1437,54 @@ async function chartRoutes(fastify, options) {
1247
1437
  }
1248
1438
  }
1249
1439
  }
1440
+ const compareConfig = chart.chart?.compare;
1441
+ let compareData;
1442
+ if (compareConfig && compareConfig.length > 0) {
1443
+ let startDate = params.start_date;
1444
+ let endDate = params.end_date;
1445
+ const dateRange = params.date_range;
1446
+ if (!startDate || !endDate) {
1447
+ if (isRelativeDateRange(params.date_range)) {
1448
+ const resolved = expandRelativeDateRange(params.date_range);
1449
+ startDate = resolved.start_date;
1450
+ endDate = resolved.end_date;
1451
+ } else if (isCustomDateRange(params.date_range)) {
1452
+ const resolved = expandCustomDateRange(params.date_range);
1453
+ startDate = resolved.start_date;
1454
+ endDate = resolved.end_date;
1455
+ } else if (dateRange && isDatePreset(dateRange)) {
1456
+ const resolved = expandDatePreset(dateRange);
1457
+ if (resolved) {
1458
+ startDate = resolved.start_date;
1459
+ endDate = resolved.end_date;
1460
+ }
1461
+ }
1462
+ }
1463
+ if (startDate && endDate) {
1464
+ compareData = [];
1465
+ for (const comp of compareConfig) {
1466
+ try {
1467
+ const periodMap = {
1468
+ previous_week: "last_7_days",
1469
+ previous_month: "last_30_days",
1470
+ previous_quarter: "last_90_days",
1471
+ previous_year: "last_365_days"
1472
+ };
1473
+ const prev = computePreviousPeriod(startDate, endDate, periodMap[comp.period] ?? comp.period);
1474
+ const prevLabel = comp.label ?? comp.period.replace(/_/g, " ");
1475
+ const { date_range: _, ...restParams } = params;
1476
+ const prevParams = { ...restParams, start_date: prev.start_date, end_date: prev.end_date };
1477
+ const prevResult = await queryService.executeChart(chart, prevParams, getUserContext(request));
1478
+ compareData.push({
1479
+ period: comp.period,
1480
+ label: prevLabel,
1481
+ rows: prevResult.rows
1482
+ });
1483
+ } catch {
1484
+ }
1485
+ }
1486
+ }
1487
+ }
1250
1488
  reply.header("X-Cache", result.cached ? "HIT" : "MISS");
1251
1489
  reply.header("X-Query-Duration-Ms", result.durationMs.toFixed(0));
1252
1490
  const meta = {
@@ -1254,7 +1492,8 @@ async function chartRoutes(fastify, options) {
1254
1492
  durationMs: result.durationMs,
1255
1493
  rowCount: result.rowCount,
1256
1494
  cacheKey: result.cacheKey,
1257
- compiledSql: result.compiledSql
1495
+ compiledSql: result.compiledSql,
1496
+ ...serverPaginated ? { serverPaginated: true, totalCount } : {}
1258
1497
  };
1259
1498
  const response = {
1260
1499
  columns: result.columns,
@@ -1274,6 +1513,9 @@ async function chartRoutes(fastify, options) {
1274
1513
  if (comparison) {
1275
1514
  response.comparison = comparison;
1276
1515
  }
1516
+ if (compareData && compareData.length > 0) {
1517
+ response.compareData = compareData;
1518
+ }
1277
1519
  let goalData = void 0;
1278
1520
  const goals = chart.chart?.goals;
1279
1521
  const modelGoal = goals?.find((g) => g.type === "model" && g.source?.model);
@@ -1331,6 +1573,38 @@ async function chartRoutes(fastify, options) {
1331
1573
  return reply.status(500).send({ error: message, errorType: classifyError(error2) });
1332
1574
  }
1333
1575
  });
1576
+ fastify.get("/api/charts/:name/export", async (request, reply) => {
1577
+ const { name } = request.params;
1578
+ const params = { ...request.query };
1579
+ const chart = configLoader.getChartByName(name);
1580
+ if (!chart) {
1581
+ const resp = chartNotFoundResponse(configLoader, name);
1582
+ return reply.status(resp.status).send(resp.body);
1583
+ }
1584
+ const project = configLoader.getProject();
1585
+ const chartExportConfig = chart.chart?.export;
1586
+ if (chartExportConfig?.enabled === false) {
1587
+ return reply.status(403).send({ error: "Export is disabled for this chart", errorType: "validation_error" });
1588
+ }
1589
+ const maxExportRows = chartExportConfig?.max_rows ?? project?.defaults?.table?.max_export_rows ?? 5e5;
1590
+ try {
1591
+ const result = await queryService.executeChartForExport(chart, params, maxExportRows, getUserContext(request));
1592
+ reply.header("Content-Type", "text/csv; charset=utf-8");
1593
+ reply.header("Content-Disposition", `attachment; filename="${name}.csv"`);
1594
+ reply.header("X-Total-Rows", String(result.rowCount));
1595
+ const columns = result.columns.map((c) => c.name);
1596
+ const headerLine = columns.map(escapeCSVField).join(",");
1597
+ const lines = [headerLine];
1598
+ for (const row of result.rows) {
1599
+ const line = columns.map((col) => escapeCSVField(String(row[col] ?? ""))).join(",");
1600
+ lines.push(line);
1601
+ }
1602
+ return reply.send(lines.join("\n"));
1603
+ } catch (error2) {
1604
+ const message = error2 instanceof Error ? error2.message : "Export failed";
1605
+ return reply.status(500).send({ error: message, errorType: classifyError(error2) });
1606
+ }
1607
+ });
1334
1608
  fastify.post("/api/charts/batch", async (request, reply) => {
1335
1609
  const { charts, includeConfig } = request.body;
1336
1610
  if (!charts || !Array.isArray(charts)) {
@@ -14317,7 +14591,7 @@ async function chatRoutes(fastify, options) {
14317
14591
  systemParts.push("Output ONLY the new text to insert. Do NOT repeat the existing content.");
14318
14592
  }
14319
14593
  const systemPrompt = systemParts.join("\n");
14320
- const { AnthropicProvider } = await import("./dist-GVNWQXFR.js");
14594
+ const { AnthropicProvider } = await import("./dist-7CRX2GIR.js");
14321
14595
  const provider = new AnthropicProvider(apiKey);
14322
14596
  const response = await provider.chat({
14323
14597
  system: systemPrompt,
@@ -14653,7 +14927,8 @@ async function createServer(options) {
14653
14927
  connector,
14654
14928
  cache,
14655
14929
  models,
14656
- refs
14930
+ refs,
14931
+ dialect: defaultConnection.type
14657
14932
  });
14658
14933
  const semanticService = new SemanticService({
14659
14934
  projectDir,
@@ -14891,7 +15166,7 @@ async function runDevServer(projectDir, options) {
14891
15166
  try {
14892
15167
  const { readFileSync: readFileSync2 } = await import("fs");
14893
15168
  const { parse: parse2 } = await import("yaml");
14894
- const { resolveProjectConfig: resolveProjectConfig2, deepMerge: deepMerge3 } = await import("./dist-PINRLZVT.js");
15169
+ const { resolveProjectConfig: resolveProjectConfig2, deepMerge: deepMerge3 } = await import("./dist-4GUE24QV.js");
14895
15170
  const raw = readFileSync2(resolve2(projectDir, "yamchart.yaml"), "utf-8");
14896
15171
  const rawConfig = parse2(raw);
14897
15172
  const resolvedEnv = options.env || process.env.YAMCHART_ENV || void 0;
@@ -14931,21 +15206,33 @@ async function runDevServer(projectDir, options) {
14931
15206
  }
14932
15207
  const spinner2 = spinner("Starting server...");
14933
15208
  let server;
14934
- try {
14935
- server = await createServer({
14936
- projectDir,
14937
- port: options.port,
14938
- watch: true,
14939
- serveStatic: !options.apiOnly,
14940
- localAuth,
14941
- env: options.env
14942
- });
14943
- await server.start();
14944
- spinner2.stop();
14945
- } catch (err) {
14946
- spinner2.fail("Failed to start server");
14947
- error(err instanceof Error ? err.message : "Unknown error");
14948
- process.exit(1);
15209
+ let actualPort = options.port;
15210
+ const MAX_PORT_ATTEMPTS = 10;
15211
+ for (let attempt = 0; attempt < MAX_PORT_ATTEMPTS; attempt++) {
15212
+ try {
15213
+ server = await createServer({
15214
+ projectDir,
15215
+ port: actualPort,
15216
+ watch: true,
15217
+ serveStatic: !options.apiOnly,
15218
+ localAuth,
15219
+ env: options.env
15220
+ });
15221
+ await server.start();
15222
+ spinner2.stop();
15223
+ if (actualPort !== options.port) {
15224
+ info(`Port ${options.port} is in use, starting on port ${actualPort}`);
15225
+ }
15226
+ break;
15227
+ } catch (err) {
15228
+ if (err && typeof err === "object" && "code" in err && err.code === "EADDRINUSE" && attempt < MAX_PORT_ATTEMPTS - 1) {
15229
+ actualPort++;
15230
+ continue;
15231
+ }
15232
+ spinner2.fail("Failed to start server");
15233
+ error(err instanceof Error ? err.message : "Unknown error");
15234
+ process.exit(1);
15235
+ }
14949
15236
  }
14950
15237
  const project = server.configLoader.getProject();
14951
15238
  const charts = server.configLoader.getCharts();
@@ -14954,8 +15241,8 @@ async function runDevServer(projectDir, options) {
14954
15241
  box([
14955
15242
  `Yamchart v${options.version}`,
14956
15243
  ``,
14957
- `Dashboard: http://localhost:${options.port}`,
14958
- `API: http://localhost:${options.port}/api`,
15244
+ `Dashboard: http://localhost:${actualPort}`,
15245
+ `API: http://localhost:${actualPort}/api`,
14959
15246
  ``,
14960
15247
  `Project: ${project.name}`,
14961
15248
  `Charts: ${charts.length} loaded`,
@@ -14966,7 +15253,7 @@ async function runDevServer(projectDir, options) {
14966
15253
  ]);
14967
15254
  newline();
14968
15255
  if (options.open && !options.apiOnly) {
14969
- const url = `http://localhost:${options.port}`;
15256
+ const url = `http://localhost:${actualPort}`;
14970
15257
  const { exec } = await import("child_process");
14971
15258
  const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
14972
15259
  exec(`${command} ${url}`);
@@ -14983,4 +15270,4 @@ async function runDevServer(projectDir, options) {
14983
15270
  export {
14984
15271
  runDevServer
14985
15272
  };
14986
- //# sourceMappingURL=dev-JUA73B6D.js.map
15273
+ //# sourceMappingURL=dev-6QGAB4ZH.js.map