@bonnard/mcp-charts 0.1.3 → 0.2.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.
@@ -1,5 +1,5 @@
1
1
  import { Pool } from 'pg';
2
- import { C as ChartData } from './types-6ALzXWjE.js';
2
+ import { C as ChartData } from './types-DUKpye7m.js';
3
3
 
4
4
  /** A Postgres result column: name + the type OID (`dataTypeID` from pg/PGlite result `fields`). */
5
5
  interface PostgresField {
package/dist/postgres.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  assertReadOnlySql,
3
3
  buildChartData,
4
4
  defaultNormalizeCell
5
- } from "./chunk-I3HINKHN.js";
5
+ } from "./chunk-IXRGLZX2.js";
6
6
 
7
7
  // src/adapters/postgres.ts
8
8
  var OID = {
@@ -1,5 +1,5 @@
1
1
  import { Connection } from 'snowflake-sdk';
2
- import { C as ChartData } from './types-6ALzXWjE.js';
2
+ import { C as ChartData } from './types-DUKpye7m.js';
3
3
 
4
4
  /** A Snowflake result column: name + the logical type from `Column.getType()`. */
5
5
  interface SnowflakeColumn {
package/dist/snowflake.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  assertReadOnlySql,
3
3
  buildChartData,
4
4
  defaultNormalizeCell
5
- } from "./chunk-I3HINKHN.js";
5
+ } from "./chunk-IXRGLZX2.js";
6
6
 
7
7
  // src/adapters/snowflake.ts
8
8
  var NUMERIC = /* @__PURE__ */ new Set(["fixed", "real"]);
@@ -0,0 +1,35 @@
1
+ import { i as FieldKind, C as ChartData } from './types-DUKpye7m.js';
2
+
3
+ /** A source column: its name + the engine's declared type, in whatever shape the driver reports. */
4
+ interface SourceColumn {
5
+ name: string;
6
+ /** Engine type, passed verbatim to mapKind (e.g. "INT64", a Postgres OID, "VARCHAR", a field object). */
7
+ type: unknown;
8
+ }
9
+ /** Map an engine's column type to our FieldKind. The one piece of real per-engine work. */
10
+ type KindMapper = (type: unknown, column: SourceColumn) => FieldKind;
11
+ /** Coerce one cell value to a flat scalar, guided by the resolved kind. */
12
+ type CellNormalizer = (value: unknown, kind: FieldKind, column: SourceColumn) => unknown;
13
+ interface BuildChartDataOptions {
14
+ rows: Record<string, unknown>[];
15
+ columns: SourceColumn[];
16
+ mapKind: KindMapper;
17
+ /** Optional; defaults to {@link defaultNormalizeCell}, which suits drivers that return JS-native values. */
18
+ normalizeCell?: CellNormalizer;
19
+ }
20
+ /** Default cell normalizer: pass scalars through, coerce numbers/booleans, stringify non-scalars.
21
+ * Handles `{ value }` wrapper objects (some drivers wrap typed values). Adapters whose driver
22
+ * needs special handling (e.g. BigQuery's typed-string + wrapper mix) supply their own. */
23
+ declare function defaultNormalizeCell(value: unknown, kind: FieldKind): unknown;
24
+ /**
25
+ * Turn a SQL result (rows + column types) into typed ChartData. Builds a complete FieldMeta per
26
+ * column from the engine kind + name-based format/granularity hints, then normalizes every cell.
27
+ */
28
+ declare function buildChartData({ rows, columns, mapKind, normalizeCell, }: BuildChartDataOptions): ChartData;
29
+ /**
30
+ * Reject anything that isn't a single SELECT/WITH statement. A cheap check on LLM-authored SQL;
31
+ * enforce real read-only access with a database role.
32
+ */
33
+ declare function assertReadOnlySql(sql: string): void;
34
+
35
+ export { type BuildChartDataOptions as B, type CellNormalizer as C, type KindMapper as K, type SourceColumn as S, assertReadOnlySql as a, buildChartData as b, defaultNormalizeCell as d };
@@ -118,6 +118,68 @@ interface ResolveOptions {
118
118
  target?: number;
119
119
  average?: boolean;
120
120
  };
121
+ /** Promote encoding-failure advisories (zero series, ignored encode column) from notes to
122
+ * thrown errors. For authoring/CI: `explain(rows, { chartType, strict: true })` fails loudly
123
+ * on a bad encoding instead of returning a blank chart. Default false (production posture). */
124
+ strict?: boolean;
125
+ }
126
+ /** Compact diagnostic from explain(): the inferred typing + resolved encoding, WITHOUT the render
127
+ * payload. Lets a dev assert the encoding in a unit test / CI against sample or live rows. */
128
+ interface ChartExplanation {
129
+ fields: {
130
+ name: string;
131
+ kind: FieldKind;
132
+ role: FieldRole;
133
+ }[];
134
+ chartType: ChartType;
135
+ x: string;
136
+ series: string[];
137
+ notes: string[];
138
+ }
139
+ /** A single KPI tile: a headline number with optional signed delta and caption. */
140
+ interface KpiTile {
141
+ type: "kpi";
142
+ /** Stable id for uniform addressability. v1 render_view item selection renders chart cells only. */
143
+ id?: string;
144
+ label: string;
145
+ value: number | string | null;
146
+ format?: FieldFormat;
147
+ currency?: string;
148
+ /** percent: value is a 0-1 fraction (renderer scales by 100). */
149
+ fraction?: boolean;
150
+ /** signed change vs prior period, same unit as value. */
151
+ delta?: number;
152
+ deltaFraction?: boolean;
153
+ /** e.g. "vs last month". */
154
+ caption?: string;
155
+ span?: number;
156
+ }
157
+ /** A block of plain text (escaped by the renderer; markdown is a later decision). */
158
+ interface TextBlock {
159
+ type: "text";
160
+ /** Stable id for uniform addressability. v1 render_view item selection renders chart cells only. */
161
+ id?: string;
162
+ text: string;
163
+ heading?: string;
164
+ span?: number;
165
+ }
166
+ /** A dashboard cell holding one resolved chart. Presence of `spec` is the discriminant. */
167
+ interface ChartCell {
168
+ type?: "chart";
169
+ /** Stable id for addressing this cell via render_view's item_id (re-render one chart alone). */
170
+ id?: string;
171
+ spec: ChartSpec;
172
+ span?: number;
173
+ }
174
+ type DashboardItem = ChartCell | KpiTile | TextBlock;
175
+ /** Output contract for a multi-item dashboard. JSON-serializable; crosses to the widget. */
176
+ interface DashboardSpec {
177
+ title?: string;
178
+ /** default 2; renderer clamps 1..4; item spans clamp to columns. */
179
+ columns?: number;
180
+ items: DashboardItem[];
181
+ /** non-fatal advisories, same posture as ChartSpec.notes. */
182
+ notes?: string[];
121
183
  }
122
184
 
123
- export type { AxisSpec as A, ChartData as C, Encode as E, FieldMeta as F, ResolveOptions as R, SeriesSpec as S, TimeGranularity as T, ChartSpec as a, ChartContext as b, ChartType as c, FieldKind as d, ColumnSpec as e, FieldFormat as f, FieldRole as g, ReferenceLine as h, Stacking as i };
185
+ export type { AxisSpec as A, ChartData as C, DashboardSpec as D, Encode as E, FieldMeta as F, KpiTile as K, ResolveOptions as R, SeriesSpec as S, TextBlock as T, ChartSpec as a, ChartCell as b, ChartExplanation as c, ChartContext as d, ChartType as e, ColumnSpec as f, DashboardItem as g, FieldFormat as h, FieldKind as i, FieldRole as j, ReferenceLine as k, Stacking as l, TimeGranularity as m };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bonnard/mcp-charts",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Add beautiful, agent-ready charts to your MCP server in a few lines.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -20,11 +20,18 @@
20
20
  "files": [
21
21
  "dist"
22
22
  ],
23
+ "bin": {
24
+ "mcp-charts": "./dist/cli.js"
25
+ },
23
26
  "exports": {
24
27
  ".": {
25
28
  "types": "./dist/index.d.ts",
26
29
  "import": "./dist/index.js"
27
30
  },
31
+ "./fixtures": {
32
+ "types": "./dist/fixtures.d.ts",
33
+ "import": "./dist/fixtures.js"
34
+ },
28
35
  "./bigquery": {
29
36
  "types": "./dist/bigquery.d.ts",
30
37
  "import": "./dist/bigquery.js"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/resolve/infer.ts","../src/adapters/sql.ts"],"sourcesContent":["// Typing inference: turn a ChartData into a complete, role-tagged FieldMeta list.\n// Priority: declared fields win; anything missing is sniffed from the row values.\n// This is what lets resolve() decide x / y / series when the data source did not\n// supply full typing (e.g. raw SQL rows).\nimport type { ChartData, FieldFormat, FieldKind, FieldMeta, FieldRole, TimeGranularity } from \"../types.js\";\n\n// Period-string -> granularity. Lets the raw-SQL path recognize time buckets that aren't full ISO\n// dates (e.g. strftime('%Y-%m') -> \"2025-01\") so time series are typed TEMPORAL — ordered, drawn\n// vertically, nicely labelled — instead of being mistaken for high-cardinality categories. Used\n// when the data source declares no column types, so the kind is inferred from the value shape.\nexport function sniffTimeGranularity(value: unknown): TimeGranularity | null {\n if (typeof value !== \"string\") return null;\n if (/^\\d{4}-\\d{2}-\\d{2}([T ]|$)/.test(value)) return \"day\"; // 2025-01-15 or a full datetime\n if (/^\\d{4}-\\d{2}$/.test(value)) return \"month\"; // 2025-01\n if (/^\\d{4}-?Q[1-4]$/i.test(value)) return \"quarter\"; // 2025-Q1 / 2025Q1\n if (/^\\d{4}-W\\d{2}$/i.test(value)) return \"week\"; // 2025-W03 (ISO week)\n if (/^\\d{4}$/.test(value)) {\n const y = Number(value); // bare year as a string (\"2025\"); guard the range to avoid 4-digit codes\n if (y >= 1900 && y <= 2100) return \"year\";\n }\n return null;\n}\n\n// Granularity from the actual values. date_trunc('month'|'quarter'|'year'|'week') yields FULL\n// dates, so a single value's shape reads as \"day\" and a monthly series gets ~30x null-filled\n// into disconnected dots. Scan the distinct dates instead: all Jan 1 -> year, all first-of-\n// quarter spaced like quarters -> quarter, all first-of-month -> month, all the same weekday ->\n// week, else day. Period strings (YYYY-MM, YYYY-Qn, ...) state their own granularity; mixed or\n// unparseable values bail out (null).\nconst DAY_MS = 86_400_000;\nexport function sniffGranularityFromValues(values: unknown[]): TimeGranularity | null {\n const seen = new Set<string>();\n const dates: Date[] = [];\n for (const v of values) {\n if (v == null) continue;\n const g = sniffTimeGranularity(v);\n if (g === null) return null;\n if (g !== \"day\") return g;\n const day = String(v).slice(0, 10);\n if (seen.has(day)) continue;\n seen.add(day);\n const d = new Date(`${day}T00:00:00.000Z`);\n if (isNaN(d.getTime())) return null;\n dates.push(d);\n }\n if (dates.length === 0) return null;\n if (dates.length === 1) return \"day\"; // one distinct date: no periodicity to read\n const times = dates.map((d) => d.getTime()).sort((a, b) => a - b);\n let minGap = Infinity;\n for (let i = 1; i < times.length; i++) minGap = Math.min(minGap, times[i]! - times[i - 1]!);\n const all = (p: (d: Date) => boolean) => dates.every(p);\n if (all((d) => d.getUTCDate() === 1)) {\n if (all((d) => d.getUTCMonth() === 0)) return \"year\";\n // First-of-quarter alone also matches monthly data (Jan, Feb, ...); the gap disambiguates.\n if (all((d) => d.getUTCMonth() % 3 === 0) && minGap > 31 * DAY_MS) return \"quarter\";\n return \"month\";\n }\n if (all((d) => d.getUTCDay() === dates[0]!.getUTCDay())) return \"week\";\n return \"day\";\n}\n\n// One value can lie (a text column whose first value is \"2024\" or \"2025-01-15\" would type the\n// whole column time/number), so sample several and require consensus; disagreement -> string.\nconst KIND_SAMPLE = 20;\nexport function sniffKind(rows: Record<string, unknown>[], name: string): FieldKind {\n const kindOf = (v: unknown): FieldKind => {\n if (typeof v === \"number\" || typeof v === \"bigint\") return \"number\";\n if (typeof v === \"boolean\") return \"boolean\";\n if (typeof v === \"string\" && sniffTimeGranularity(v) !== null) return \"time\";\n return \"string\";\n };\n let kind: FieldKind | undefined;\n let seen = 0;\n for (const r of rows) {\n const v = r[name];\n if (v == null) continue;\n const k = kindOf(v);\n if (kind === undefined) kind = k;\n else if (k !== kind) return \"string\";\n if (++seen >= KIND_SAMPLE) break;\n }\n return kind ?? \"string\";\n}\n\nexport function roleFromKind(kind: FieldKind): FieldRole {\n if (kind === \"time\") return \"time\";\n if (kind === \"number\") return \"measure\";\n return \"dimension\";\n}\n\nexport function titleCase(s: string): string {\n return s.replace(/_/g, \" \").replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\n// Name-based hints — a purely conventional fallback used only when the data source declares no\n// format/granularity. Centralized here so the adapter path (buildChartData) and the raw-rows path\n// (inferFields) apply identical rules.\n\n// A numeric column whose name reads as a percentage renders as a percent. pct/percent/percentage\n// names are unambiguous; rate/ratio names are not (exchange_rate at 1.08, hourly_rate at 45), so\n// they only hold when no value contradicts a 0-1 fraction reading. Currency is deliberately NOT\n// guessed from names (the code is unknowable) — declare it. camelCase is normalized to snake.\nexport function formatHint(name: string, values?: unknown[]): FieldFormat | undefined {\n const n = name.replace(/([a-z0-9])([A-Z])/g, \"$1_$2\").toLowerCase();\n if (/(^|_)(pct|percent|percentage)(_|$)/.test(n)) return \"percent\";\n if (/(^|_)(rate|ratio)(_|$)/.test(n)) {\n for (const v of values ?? []) {\n if (v == null) continue;\n const x = Number(v);\n if (Number.isFinite(x) && Math.abs(x) > 1) return undefined;\n }\n return \"percent\";\n }\n return undefined;\n}\n\n// Granularity from the column name, for time columns whose values don't reveal it (e.g. a DATE\n// named \"week_start\" holding full dates). Defaults to day.\nexport function granularityHint(name: string): TimeGranularity {\n const n = name.toLowerCase();\n if (n.includes(\"year\")) return \"year\";\n if (n.includes(\"quarter\")) return \"quarter\";\n if (n.includes(\"month\")) return \"month\";\n if (n.includes(\"week\")) return \"week\";\n return \"day\";\n}\n\n/** Complete field metadata for every column, declared values taking precedence. */\nexport function inferFields(data: ChartData): FieldMeta[] {\n const { rows, fields } = data;\n const declared = new Map((fields ?? []).map((f) => [f.name, f]));\n // Union of returned columns + any declared-only names: declaring fields for SOME columns\n // augments their typing, it does not drop the columns you didn't declare.\n const rowKeys = rows[0] ? Object.keys(rows[0]) : [];\n const names = [...rowKeys, ...[...declared.keys()].filter((n) => !rowKeys.includes(n))];\n\n return names.map((name) => {\n const d = declared.get(name);\n const kind: FieldKind = d?.kind ?? sniffKind(rows, name);\n const role: FieldRole = d?.role ?? roleFromKind(kind);\n // Time columns with no declared granularity: infer it from the values (YYYY-MM -> month,\n // all first-of-month full dates -> month). declared > value-scan > name-hint\n const granularity =\n d?.granularity ??\n (kind === \"time\"\n ? (sniffGranularityFromValues(rows.map((r) => r[name])) ?? granularityHint(name))\n : undefined);\n // declared > name-hint (rate -> percent); only for numeric columns\n const format = d?.format ?? (kind === \"number\" ? formatHint(name, rows.map((r) => r[name])) : undefined);\n return {\n name,\n kind,\n role,\n label: d?.label ?? titleCase(name),\n ...(format && { format }),\n ...(granularity && { granularity }),\n ...(d?.additive != null && { additive: d.additive }),\n ...(d?.currency && { currency: d.currency }),\n };\n });\n}\n","// Shared adapter core. An adapter's only engine-specific jobs are (a) report each column's engine\n// type, (b) map that type to a FieldKind, and (c) normalize a cell to a flat scalar. The rest —\n// assembling typed FieldMeta (with name-based format/granularity hints), the ChartData shape, and\n// the read-only check — lives here so every adapter shares it.\n//\n// Connection, auth, read-only enforcement, cost caps and timeouts belong to the caller's database\n// role; assertReadOnlySql is a cheap extra check on LLM-authored SQL, not a substitute for one.\nimport type { ChartData, FieldKind, FieldMeta } from \"../types.js\";\nimport { roleFromKind, titleCase, formatHint, granularityHint, sniffGranularityFromValues } from \"../resolve/infer.js\";\n\n/** A source column: its name + the engine's declared type, in whatever shape the driver reports. */\nexport interface SourceColumn {\n name: string;\n /** Engine type, passed verbatim to mapKind (e.g. \"INT64\", a Postgres OID, \"VARCHAR\", a field object). */\n type: unknown;\n}\n\n/** Map an engine's column type to our FieldKind. The one piece of real per-engine work. */\nexport type KindMapper = (type: unknown, column: SourceColumn) => FieldKind;\n\n/** Coerce one cell value to a flat scalar, guided by the resolved kind. */\nexport type CellNormalizer = (value: unknown, kind: FieldKind, column: SourceColumn) => unknown;\n\nexport interface BuildChartDataOptions {\n rows: Record<string, unknown>[];\n columns: SourceColumn[];\n mapKind: KindMapper;\n /** Optional; defaults to {@link defaultNormalizeCell}, which suits drivers that return JS-native values. */\n normalizeCell?: CellNormalizer;\n}\n\n/** Default cell normalizer: pass scalars through, coerce numbers/booleans, stringify non-scalars.\n * Handles `{ value }` wrapper objects (some drivers wrap typed values). Adapters whose driver\n * needs special handling (e.g. BigQuery's typed-string + wrapper mix) supply their own. */\nexport function defaultNormalizeCell(value: unknown, kind: FieldKind): unknown {\n if (value == null) return null;\n const obj = typeof value === \"object\" ? (value as Record<string, unknown>) : null;\n if (kind === \"number\") {\n const raw = obj ? (\"value\" in obj ? obj.value : (value as { toString(): string }).toString()) : value;\n const n = Number(raw);\n return Number.isFinite(n) ? n : null;\n }\n if (kind === \"boolean\") {\n if (typeof value === \"boolean\") return value;\n const s = String(obj && \"value\" in obj ? obj.value : value).toLowerCase();\n return s === \"true\" || s === \"1\" ? true : s === \"false\" || s === \"0\" ? false : null;\n }\n if (kind === \"time\") {\n if (obj && \"value\" in obj) return String(obj.value);\n return value instanceof Date ? value.toISOString() : typeof value === \"string\" ? value : String(value);\n }\n // string-ish: unwrap { value }, stringify arrays/objects so the scalar guard passes, else pass through.\n if (obj) {\n if (Array.isArray(value)) return JSON.stringify(value);\n if (\"value\" in obj) return String(obj.value);\n return JSON.stringify(value);\n }\n return value;\n}\n\n/**\n * Turn a SQL result (rows + column types) into typed ChartData. Builds a complete FieldMeta per\n * column from the engine kind + name-based format/granularity hints, then normalizes every cell.\n */\nexport function buildChartData({\n rows,\n columns,\n mapKind,\n normalizeCell = defaultNormalizeCell,\n}: BuildChartDataOptions): ChartData {\n const kindByName = new Map(columns.map((col) => [col.name, mapKind(col.type, col)]));\n const out = rows.map((row) => {\n const r: Record<string, unknown> = {};\n for (const col of columns) r[col.name] = normalizeCell(row[col.name], kindByName.get(col.name)!, col);\n return r;\n });\n const fields: FieldMeta[] = columns.map((col) => {\n const kind = kindByName.get(col.name)!;\n const format = kind === \"number\" ? formatHint(col.name, out.map((r) => r[col.name])) : undefined;\n // Granularity from the normalized values (all first-of-month -> month); name-hint fallback.\n const granularity =\n kind === \"time\"\n ? (sniffGranularityFromValues(out.map((r) => r[col.name])) ?? granularityHint(col.name))\n : undefined;\n return {\n name: col.name,\n kind,\n role: roleFromKind(kind),\n label: titleCase(col.name),\n ...(format && { format }),\n ...(granularity && { granularity }),\n };\n });\n return { rows: out, fields };\n}\n\n/**\n * Reject anything that isn't a single SELECT/WITH statement. A cheap check on LLM-authored SQL;\n * enforce real read-only access with a database role.\n */\nexport function assertReadOnlySql(sql: string): void {\n const t = sql.trim().replace(/;\\s*$/, \"\");\n if (/;/.test(t)) throw new Error(\"Only a single statement is allowed.\");\n if (!/^(select|with)\\b/i.test(t)) throw new Error(\"Only read-only SELECT queries are allowed.\");\n if (\n /\\b(insert|update|delete|merge|drop|alter|create|truncate|grant|revoke|call|export|load|copy|execute|attach|vacuum|lock)\\b/i.test(\n t,\n )\n ) {\n throw new Error(\"Write/DDL statements are not allowed.\");\n }\n}\n"],"mappings":"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","names":[]}