@metalcloud/dashboard-schema 0.0.0-stage → 0.3.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.
package/dist/index.js ADDED
@@ -0,0 +1,373 @@
1
+ // src/primitives.ts
2
+ import { z } from "zod";
3
+ var IdSchema = z.string().regex(/^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/, "Id must start with a letter and use only letters, digits, '_' or '-' (max 64)");
4
+ var DataPathSchema = z.string().min(1).regex(/^[^\s()[\]{};'"`]+$/, "Data path must be a plain dot path (no spaces or expressions)");
5
+ var ToneSchema = z.enum(["success", "warning", "error", "info", "neutral"]);
6
+ var SizeSchema = z.enum(["sm", "md", "lg"]);
7
+ var JsonPrimitiveSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
8
+
9
+ // src/refs.ts
10
+ import { z as z2 } from "zod";
11
+ var RefPath = z2.string().regex(/^[a-zA-Z][a-zA-Z0-9_-]*(\.[a-zA-Z0-9_-]+)*$/, "Reference must be 'id' or 'id.path'");
12
+ var FilterRefSchema = z2.object({ $filter: RefPath }).strict();
13
+ var VarRefSchema = z2.object({ $var: RefPath }).strict();
14
+ var RowRefSchema = z2.object({ $row: z2.string().min(1) }).strict();
15
+ var RefSchema = z2.union([FilterRefSchema, VarRefSchema]);
16
+ var ParamValueSchema = z2.lazy(
17
+ () => z2.union([JsonPrimitiveSchema, FilterRefSchema, VarRefSchema, z2.array(ParamValueSchema), z2.record(ParamValueSchema)])
18
+ );
19
+ var ActionValueSchema = z2.union([RowRefSchema, ParamValueSchema]);
20
+ var isFilterRef = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && typeof v.$filter === "string" && Object.keys(v).length === 1;
21
+ var isVarRef = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && typeof v.$var === "string" && Object.keys(v).length === 1;
22
+ var isRowRef = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && typeof v.$row === "string" && Object.keys(v).length === 1;
23
+
24
+ // src/filters.ts
25
+ import { z as z3 } from "zod";
26
+ var DATE_PRESETS = ["today", "yesterday", "last7d", "last30d", "last90d", "thisWeek", "thisMonth", "lastMonth", "thisYear"];
27
+ var DatePresetSchema = z3.enum(DATE_PRESETS);
28
+ var IsoDate = z3.string().regex(/^\d{4}-\d{2}-\d{2}(T[\d:.]+(Z|[+-]\d{2}:\d{2})?)?$/, "Expected an ISO date (YYYY-MM-DD) or datetime");
29
+ var DateRangeValueSchema = z3.union([
30
+ z3.object({ preset: DatePresetSchema }).strict(),
31
+ z3.object({ from: IsoDate, to: IsoDate }).strict()
32
+ ]);
33
+ var FilterOptionsSchema = z3.object({
34
+ static: z3.array(z3.object({ label: z3.string(), value: JsonPrimitiveSchema })).optional(),
35
+ dataSource: IdSchema.optional(),
36
+ labelKey: DataPathSchema.optional(),
37
+ valueKey: DataPathSchema.optional()
38
+ }).passthrough().refine((o) => o.static !== void 0 !== (o.dataSource !== void 0), {
39
+ message: "Provide exactly one of options.static or options.dataSource"
40
+ });
41
+ var base = {
42
+ id: IdSchema,
43
+ label: z3.string().min(1),
44
+ /** Not shown in the filter bar; set by widgets (e.g. clicking a stage tile). */
45
+ hidden: z3.boolean().optional()
46
+ };
47
+ var DateRangeFilterSchema = z3.object({ ...base, type: z3.literal("dateRange"), default: DateRangeValueSchema.optional(), presets: z3.array(DatePresetSchema).optional() }).passthrough();
48
+ var SelectFilterSchema = z3.object({
49
+ ...base,
50
+ type: z3.literal("select"),
51
+ default: JsonPrimitiveSchema.optional(),
52
+ options: FilterOptionsSchema,
53
+ clearable: z3.boolean().optional(),
54
+ /** Text shown when nothing is selected, e.g. "All" → "Line (All)". */
55
+ allLabel: z3.string().optional(),
56
+ /** Show ← → arrows that step through the options. */
57
+ stepper: z3.boolean().optional()
58
+ }).passthrough();
59
+ var MultiSelectFilterSchema = z3.object({ ...base, type: z3.literal("multiSelect"), default: z3.array(JsonPrimitiveSchema).optional(), options: FilterOptionsSchema, allLabel: z3.string().optional() }).passthrough();
60
+ var SearchFilterSchema = z3.object({ ...base, type: z3.literal("search"), default: z3.string().optional(), debounceMs: z3.number().int().min(0).max(5e3).optional() }).passthrough();
61
+ var ToggleFilterSchema = z3.object({ ...base, type: z3.literal("toggle"), default: z3.boolean().optional() }).passthrough();
62
+ var FilterDefSchema = z3.discriminatedUnion("type", [
63
+ DateRangeFilterSchema,
64
+ SelectFilterSchema,
65
+ MultiSelectFilterSchema,
66
+ SearchFilterSchema,
67
+ ToggleFilterSchema
68
+ ]);
69
+ var FILTER_TYPES = ["dateRange", "select", "multiSelect", "search", "toggle"];
70
+
71
+ // src/dataSources.ts
72
+ import { z as z4 } from "zod";
73
+ var TransformStepSchema = z4.union([
74
+ z4.string().min(1),
75
+ z4.object({ name: z4.string().min(1), args: z4.record(ParamValueSchema).optional() }).strict()
76
+ ]);
77
+ var HttpRequestSchema = z4.object({
78
+ url: z4.string().min(1).refine((u) => !/^\s*(javascript|data|vbscript):/i.test(u), "Unsafe URL scheme"),
79
+ method: z4.enum(["GET", "POST"]).optional(),
80
+ params: z4.record(ParamValueSchema).optional(),
81
+ body: ParamValueSchema.optional()
82
+ }).passthrough();
83
+ var HttpDataSourceSchema = z4.object({
84
+ id: IdSchema,
85
+ kind: z4.literal("http"),
86
+ request: HttpRequestSchema,
87
+ transform: z4.array(TransformStepSchema).optional(),
88
+ refreshIntervalSec: z4.number().int().min(5).optional()
89
+ }).passthrough();
90
+ var StaticDataSourceSchema = z4.object({
91
+ id: IdSchema,
92
+ kind: z4.literal("static"),
93
+ static: z4.unknown(),
94
+ transform: z4.array(TransformStepSchema).optional()
95
+ }).passthrough();
96
+ var DataSourceDefSchema = z4.discriminatedUnion("kind", [HttpDataSourceSchema, StaticDataSourceSchema]);
97
+
98
+ // src/conditions.ts
99
+ import { z as z5 } from "zod";
100
+ var ConditionSchema = z5.lazy(
101
+ () => z5.union([
102
+ z5.object({ op: z5.enum(["eq", "neq", "gt", "gte", "lt", "lte"]), left: RefSchema, right: z5.union([RefSchema, JsonPrimitiveSchema]) }).strict(),
103
+ z5.object({ op: z5.enum(["in", "nin"]), left: RefSchema, right: z5.array(JsonPrimitiveSchema) }).strict(),
104
+ z5.object({ op: z5.enum(["empty", "notEmpty"]), left: RefSchema }).strict(),
105
+ z5.object({ op: z5.enum(["and", "or"]), conditions: z5.array(ConditionSchema).min(1) }).strict(),
106
+ z5.object({ op: z5.literal("not"), condition: ConditionSchema }).strict()
107
+ ])
108
+ );
109
+ var MAX_CONDITION_DEPTH = 5;
110
+ function conditionDepth(c) {
111
+ if ("conditions" in c) return 1 + Math.max(...c.conditions.map(conditionDepth));
112
+ if ("condition" in c) return 1 + conditionDepth(c.condition);
113
+ return 1;
114
+ }
115
+
116
+ // src/actions.ts
117
+ import { z as z6 } from "zod";
118
+ var TriggerSchema = z6.enum(["click", "rowClick"]);
119
+ var vars = z6.record(ActionValueSchema).optional();
120
+ var NavigateActionSchema = z6.object({ on: TriggerSchema, type: z6.literal("navigate"), params: z6.object({ to: z6.string().min(1), query: vars }).passthrough() }).passthrough();
121
+ var SetFilterActionSchema = z6.object({ on: TriggerSchema, type: z6.literal("setFilter"), params: z6.object({ filter: IdSchema, value: ActionValueSchema }).passthrough() }).passthrough();
122
+ var DrilldownActionSchema = z6.object({ on: TriggerSchema, type: z6.literal("drilldown"), params: z6.object({ dashboardId: IdSchema, variables: vars }).passthrough() }).passthrough();
123
+ var OpenModalActionSchema = z6.object({ on: TriggerSchema, type: z6.literal("openModal"), params: z6.object({ widget: IdSchema, title: z6.string().optional(), variables: vars }).passthrough() }).passthrough();
124
+ var ActionDefSchema = z6.discriminatedUnion("type", [NavigateActionSchema, SetFilterActionSchema, DrilldownActionSchema, OpenModalActionSchema]);
125
+
126
+ // src/widgets.ts
127
+ import { z as z7 } from "zod";
128
+ var int = z7.number().int();
129
+ var GridPosSchema = z7.object({ x: int.min(0).max(11), y: int.min(0), w: int.min(1).max(12), h: int.min(1), minW: int.min(1).max(12).optional(), minH: int.min(1).optional() }).passthrough();
130
+ var WidgetLayoutSchema = GridPosSchema.extend({
131
+ responsive: z7.object({ md: GridPosSchema.optional(), sm: GridPosSchema.optional(), xs: GridPosSchema.optional() }).optional()
132
+ }).passthrough();
133
+ var WidgetDefSchema = z7.object({
134
+ id: IdSchema,
135
+ type: z7.string().min(1),
136
+ title: z7.string().optional(),
137
+ subtitle: z7.string().optional(),
138
+ /** Text for the ⓘ tooltip next to the title. */
139
+ info: z7.string().max(2e3).optional(),
140
+ /** Short text on the right of the header, e.g. "Total: 20 heats". */
141
+ meta: z7.string().max(200).optional(),
142
+ /** Show a "Live · updated just now" badge (refreshes with the data). */
143
+ live: z7.boolean().optional(),
144
+ layout: WidgetLayoutSchema,
145
+ dataSource: IdSchema.optional(),
146
+ mapping: z7.record(DataPathSchema).optional(),
147
+ options: z7.record(z7.unknown()).optional(),
148
+ listensTo: z7.array(IdSchema).optional(),
149
+ actions: z7.array(ActionDefSchema).optional(),
150
+ visibleWhen: ConditionSchema.optional()
151
+ }).passthrough();
152
+
153
+ // src/dashboard.ts
154
+ import { z as z8 } from "zod";
155
+ var CURRENT_SCHEMA_VERSION = 1;
156
+ var LayoutDefSchema = z8.object({
157
+ columns: z8.literal(12),
158
+ rowHeight: z8.number().int().min(20).max(200),
159
+ breakpoints: z8.object({ lg: z8.number().int().min(0).optional(), md: z8.number().int().min(0).optional(), sm: z8.number().int().min(0).optional(), xs: z8.number().int().min(0).optional() }).optional(),
160
+ /** Horizontal gap between cards, px (default 16). */
161
+ gapX: z8.number().int().min(0).max(48).optional(),
162
+ /** Vertical gap between rows, px (default 16). */
163
+ gapY: z8.number().int().min(0).max(48).optional(),
164
+ /** "grid": every card is h × rowHeight. "content": each row is as tall as its tallest card; charts use h × rowHeight. */
165
+ fit: z8.enum(["grid", "content"]).optional(),
166
+ /** Show the dashboard title/description above the filters (default true). */
167
+ showHeader: z8.boolean().optional()
168
+ }).passthrough();
169
+ var DashboardMetaSchema = z8.object({ createdBy: z8.string().optional(), updatedAt: z8.string().optional(), tags: z8.array(z8.string()).optional() }).passthrough();
170
+ var DashboardSchemaV1 = z8.object({
171
+ schemaVersion: z8.literal(1),
172
+ id: IdSchema,
173
+ title: z8.string().min(1),
174
+ description: z8.string().optional(),
175
+ layout: LayoutDefSchema,
176
+ filters: z8.array(FilterDefSchema).default([]),
177
+ dataSources: z8.array(DataSourceDefSchema).default([]),
178
+ widgets: z8.array(WidgetDefSchema).default([]),
179
+ meta: DashboardMetaSchema.optional()
180
+ }).passthrough();
181
+
182
+ // src/migrations/index.ts
183
+ var migrations = {};
184
+ var MigrationError = class extends Error {
185
+ constructor() {
186
+ super(...arguments);
187
+ this.name = "MigrationError";
188
+ }
189
+ };
190
+ var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
191
+ function migrateSchema(input) {
192
+ if (!isObject(input)) throw new MigrationError("Dashboard JSON must be an object");
193
+ const raw = input.schemaVersion;
194
+ if (raw === void 0) throw new MigrationError("Missing 'schemaVersion'");
195
+ if (typeof raw !== "number" || !Number.isInteger(raw) || raw < 1) throw new MigrationError(`Invalid schemaVersion: ${JSON.stringify(raw)}`);
196
+ if (raw > CURRENT_SCHEMA_VERSION) {
197
+ throw new MigrationError(`Dashboard uses schemaVersion ${raw}, but this renderer supports up to ${CURRENT_SCHEMA_VERSION}. Upgrade the renderer package.`);
198
+ }
199
+ let doc = structuredClone(input);
200
+ for (let v = raw; v < CURRENT_SCHEMA_VERSION; v++) {
201
+ const step = migrations[v];
202
+ if (!step) throw new MigrationError(`No migration registered from v${v} to v${v + 1}`);
203
+ doc = { ...step(doc), schemaVersion: v + 1 };
204
+ }
205
+ return doc;
206
+ }
207
+
208
+ // src/validate.ts
209
+ function formatPath(path) {
210
+ return path.reduce((acc, seg) => typeof seg === "number" ? `${acc}[${seg}]` : acc ? `${acc}.${seg}` : seg, "");
211
+ }
212
+ var fromZod = (i) => ({ path: formatPath(i.path), message: i.message });
213
+ var KNOWN_KEYS = {
214
+ root: ["schemaVersion", "id", "title", "description", "layout", "filters", "dataSources", "widgets", "meta"],
215
+ widget: ["id", "type", "title", "subtitle", "info", "meta", "live", "layout", "dataSource", "mapping", "options", "listensTo", "actions", "visibleWhen"]
216
+ };
217
+ function collectRefs(value, out) {
218
+ if (Array.isArray(value)) value.forEach((v) => collectRefs(v, out));
219
+ else if (isFilterRef(value)) out.push(value.$filter.split(".")[0]);
220
+ else if (typeof value === "object" && value !== null) Object.values(value).forEach((v) => collectRefs(v, out));
221
+ }
222
+ function conditionRefs(c, out) {
223
+ if ("conditions" in c) c.conditions.forEach((x) => conditionRefs(x, out));
224
+ else if ("condition" in c) conditionRefs(c.condition, out);
225
+ else collectRefs([c.left, "right" in c ? c.right : null], out);
226
+ }
227
+ function crossValidate(d) {
228
+ const errors = [];
229
+ const warnings = [];
230
+ const dupes = (items, key) => {
231
+ const seen = /* @__PURE__ */ new Set();
232
+ items.forEach((it, i) => {
233
+ if (seen.has(it.id)) errors.push({ path: `${key}[${i}].id`, message: `Duplicate id '${it.id}'` });
234
+ seen.add(it.id);
235
+ });
236
+ };
237
+ dupes(d.widgets, "widgets");
238
+ dupes(d.filters, "filters");
239
+ dupes(d.dataSources, "dataSources");
240
+ const filterIds = new Set(d.filters.map((f) => f.id));
241
+ const dsIds = new Set(d.dataSources.map((s) => s.id));
242
+ const widgetIds = new Set(d.widgets.map((w) => w.id));
243
+ const checkFilterRefs = (value, path) => {
244
+ const refs = [];
245
+ collectRefs(value, refs);
246
+ refs.forEach((r) => !filterIds.has(r) && errors.push({ path, message: `Unknown filter '${r}' in $filter reference` }));
247
+ };
248
+ d.dataSources.forEach((s, i) => {
249
+ if (s.kind === "http") checkFilterRefs(s.request, `dataSources[${i}].request`);
250
+ s.transform?.forEach((t, j) => typeof t !== "string" && checkFilterRefs(t.args, `dataSources[${i}].transform[${j}]`));
251
+ });
252
+ d.filters.forEach((f, i) => {
253
+ if ((f.type === "select" || f.type === "multiSelect") && f.options.dataSource && !dsIds.has(f.options.dataSource)) {
254
+ errors.push({ path: `filters[${i}].options.dataSource`, message: `Unknown data source '${f.options.dataSource}'` });
255
+ }
256
+ });
257
+ const sourceDeps = /* @__PURE__ */ new Map();
258
+ d.dataSources.forEach((s) => {
259
+ const refs = [];
260
+ if (s.kind === "http") collectRefs(s.request, refs);
261
+ sourceDeps.set(s.id, refs);
262
+ });
263
+ const filterSource = /* @__PURE__ */ new Map();
264
+ d.filters.forEach((f) => (f.type === "select" || f.type === "multiSelect") && f.options.dataSource && filterSource.set(f.id, f.options.dataSource));
265
+ const visit = (filterId, stack) => {
266
+ if (stack.has(filterId)) return true;
267
+ const src = filterSource.get(filterId);
268
+ if (!src) return false;
269
+ stack.add(filterId);
270
+ const cyc = (sourceDeps.get(src) ?? []).some((f) => visit(f, stack));
271
+ stack.delete(filterId);
272
+ return cyc;
273
+ };
274
+ d.filters.forEach((f, i) => visit(f.id, /* @__PURE__ */ new Set()) && errors.push({ path: `filters[${i}].options.dataSource`, message: `Filter '${f.id}' options depend on itself (cycle)` }));
275
+ d.widgets.forEach((w, i) => {
276
+ const p = `widgets[${i}]`;
277
+ if (w.dataSource && !dsIds.has(w.dataSource)) errors.push({ path: `${p}.dataSource`, message: `Unknown data source '${w.dataSource}'` });
278
+ if (w.layout.x + w.layout.w > 12) errors.push({ path: `${p}.layout`, message: `Widget overflows the 12-column grid (x + w = ${w.layout.x + w.layout.w})` });
279
+ w.listensTo?.forEach((f, j) => !filterIds.has(f) && errors.push({ path: `${p}.listensTo[${j}]`, message: `Unknown filter '${f}'` }));
280
+ if (w.visibleWhen) {
281
+ if (conditionDepth(w.visibleWhen) > MAX_CONDITION_DEPTH) errors.push({ path: `${p}.visibleWhen`, message: `Condition nesting deeper than ${MAX_CONDITION_DEPTH}` });
282
+ const refs = [];
283
+ conditionRefs(w.visibleWhen, refs);
284
+ refs.forEach((r) => !filterIds.has(r) && errors.push({ path: `${p}.visibleWhen`, message: `Unknown filter '${r}'` }));
285
+ }
286
+ w.actions?.forEach((a, j) => {
287
+ const ap = `${p}.actions[${j}].params`;
288
+ if (a.type === "setFilter" && !filterIds.has(a.params.filter)) errors.push({ path: `${ap}.filter`, message: `Unknown filter '${a.params.filter}'` });
289
+ if (a.type === "openModal" && !widgetIds.has(a.params.widget)) errors.push({ path: `${ap}.widget`, message: `Unknown widget '${a.params.widget}'` });
290
+ checkFilterRefs(a.params, ap);
291
+ });
292
+ Object.keys(w).forEach((k) => !KNOWN_KEYS.widget.includes(k) && warnings.push({ path: `${p}.${k}`, message: `Unknown field '${k}' (kept, ignored by v1 renderer)` }));
293
+ });
294
+ Object.keys(d).forEach((k) => !KNOWN_KEYS.root.includes(k) && warnings.push({ path: k, message: `Unknown field '${k}' (kept, ignored by v1 renderer)` }));
295
+ return { errors, warnings };
296
+ }
297
+ function validateSchema(json) {
298
+ let migrated;
299
+ try {
300
+ migrated = migrateSchema(json);
301
+ } catch (e) {
302
+ const message = e instanceof MigrationError ? e.message : "Could not read dashboard JSON";
303
+ return { ok: false, errors: [{ path: "schemaVersion", message }], warnings: [] };
304
+ }
305
+ const parsed = DashboardSchemaV1.safeParse(migrated);
306
+ if (!parsed.success) return { ok: false, errors: parsed.error.issues.map(fromZod), warnings: [] };
307
+ const { errors, warnings } = crossValidate(parsed.data);
308
+ if (errors.length) return { ok: false, errors, warnings };
309
+ return { ok: true, data: parsed.data, errors: [], warnings };
310
+ }
311
+ function validateJsonString(text) {
312
+ try {
313
+ return validateSchema(JSON.parse(text));
314
+ } catch (e) {
315
+ return { ok: false, errors: [{ path: "", message: e instanceof Error ? e.message : "Invalid JSON" }], warnings: [] };
316
+ }
317
+ }
318
+ export {
319
+ ActionDefSchema,
320
+ ActionValueSchema,
321
+ CURRENT_SCHEMA_VERSION,
322
+ ConditionSchema,
323
+ DATE_PRESETS,
324
+ DashboardMetaSchema,
325
+ DashboardSchemaV1,
326
+ DataPathSchema,
327
+ DataSourceDefSchema,
328
+ DatePresetSchema,
329
+ DateRangeFilterSchema,
330
+ DateRangeValueSchema,
331
+ DrilldownActionSchema,
332
+ FILTER_TYPES,
333
+ FilterDefSchema,
334
+ FilterOptionsSchema,
335
+ FilterRefSchema,
336
+ GridPosSchema,
337
+ HttpDataSourceSchema,
338
+ HttpRequestSchema,
339
+ IdSchema,
340
+ JsonPrimitiveSchema,
341
+ LayoutDefSchema,
342
+ MAX_CONDITION_DEPTH,
343
+ MigrationError,
344
+ MultiSelectFilterSchema,
345
+ NavigateActionSchema,
346
+ OpenModalActionSchema,
347
+ ParamValueSchema,
348
+ RefSchema,
349
+ RowRefSchema,
350
+ SearchFilterSchema,
351
+ SelectFilterSchema,
352
+ SetFilterActionSchema,
353
+ SizeSchema,
354
+ StaticDataSourceSchema,
355
+ ToggleFilterSchema,
356
+ ToneSchema,
357
+ TransformStepSchema,
358
+ TriggerSchema,
359
+ VarRefSchema,
360
+ WidgetDefSchema,
361
+ WidgetLayoutSchema,
362
+ conditionDepth,
363
+ crossValidate,
364
+ formatPath,
365
+ isFilterRef,
366
+ isRowRef,
367
+ isVarRef,
368
+ migrateSchema,
369
+ migrations,
370
+ validateJsonString,
371
+ validateSchema
372
+ };
373
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/primitives.ts","../src/refs.ts","../src/filters.ts","../src/dataSources.ts","../src/conditions.ts","../src/actions.ts","../src/widgets.ts","../src/dashboard.ts","../src/migrations/index.ts","../src/validate.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/** Ids may not contain dots: dots separate path segments in references. */\nexport const IdSchema = z\n .string()\n .regex(/^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/, \"Id must start with a letter and use only letters, digits, '_' or '-' (max 64)\");\nexport type Id = z.infer<typeof IdSchema>;\n\n/** Dot path into data, e.g. \"summary.total\" or \"items.0.kwh\". No expressions. */\nexport const DataPathSchema = z\n .string()\n .min(1)\n .regex(/^[^\\s()[\\]{};'\"`]+$/, \"Data path must be a plain dot path (no spaces or expressions)\");\nexport type DataPath = z.infer<typeof DataPathSchema>;\n\nexport const ToneSchema = z.enum([\"success\", \"warning\", \"error\", \"info\", \"neutral\"]);\nexport type Tone = z.infer<typeof ToneSchema>;\n\nexport const SizeSchema = z.enum([\"sm\", \"md\", \"lg\"]);\nexport type Size = z.infer<typeof SizeSchema>;\n\nexport const JsonPrimitiveSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);\nexport type JsonPrimitive = z.infer<typeof JsonPrimitiveSchema>;\n","import { z } from \"zod\";\nimport { JsonPrimitiveSchema, type JsonPrimitive } from \"./primitives\";\n\nconst RefPath = z.string().regex(/^[a-zA-Z][a-zA-Z0-9_-]*(\\.[a-zA-Z0-9_-]+)*$/, \"Reference must be 'id' or 'id.path'\");\n\n/** { \"$filter\": \"period.from\" } — filter id plus optional sub-path. */\nexport const FilterRefSchema = z.object({ $filter: RefPath }).strict();\n/** { \"$var\": \"customerId\" } — a host-provided variable. */\nexport const VarRefSchema = z.object({ $var: RefPath }).strict();\n/** { \"$row\": \"plant.id\" } — value from the clicked row/point (actions only). */\nexport const RowRefSchema = z.object({ $row: z.string().min(1) }).strict();\n\nexport type FilterRef = z.infer<typeof FilterRefSchema>;\nexport type VarRef = z.infer<typeof VarRefSchema>;\nexport type RowRef = z.infer<typeof RowRefSchema>;\nexport type Ref = FilterRef | VarRef;\nexport const RefSchema = z.union([FilterRefSchema, VarRefSchema]);\n\nexport type ParamValue = JsonPrimitive | Ref | ParamValue[] | { [key: string]: ParamValue };\nexport const ParamValueSchema: z.ZodType<ParamValue> = z.lazy(() =>\n z.union([JsonPrimitiveSchema, FilterRefSchema, VarRefSchema, z.array(ParamValueSchema), z.record(ParamValueSchema)]),\n);\n\nexport type ActionValue = ParamValue | RowRef;\nexport const ActionValueSchema: z.ZodType<ActionValue> = z.union([RowRefSchema, ParamValueSchema]);\n\nexport const isFilterRef = (v: unknown): v is FilterRef =>\n typeof v === \"object\" && v !== null && !Array.isArray(v) && typeof (v as Record<string, unknown>).$filter === \"string\" && Object.keys(v).length === 1;\nexport const isVarRef = (v: unknown): v is VarRef =>\n typeof v === \"object\" && v !== null && !Array.isArray(v) && typeof (v as Record<string, unknown>).$var === \"string\" && Object.keys(v).length === 1;\nexport const isRowRef = (v: unknown): v is RowRef =>\n typeof v === \"object\" && v !== null && !Array.isArray(v) && typeof (v as Record<string, unknown>).$row === \"string\" && Object.keys(v).length === 1;\n","import { z } from \"zod\";\nimport { DataPathSchema, IdSchema, JsonPrimitiveSchema } from \"./primitives\";\n\nexport const DATE_PRESETS = [\"today\", \"yesterday\", \"last7d\", \"last30d\", \"last90d\", \"thisWeek\", \"thisMonth\", \"lastMonth\", \"thisYear\"] as const;\nexport const DatePresetSchema = z.enum(DATE_PRESETS);\nexport type DatePreset = z.infer<typeof DatePresetSchema>;\n\nconst IsoDate = z.string().regex(/^\\d{4}-\\d{2}-\\d{2}(T[\\d:.]+(Z|[+-]\\d{2}:\\d{2})?)?$/, \"Expected an ISO date (YYYY-MM-DD) or datetime\");\nexport const DateRangeValueSchema = z.union([\n z.object({ preset: DatePresetSchema }).strict(),\n z.object({ from: IsoDate, to: IsoDate }).strict(),\n]);\nexport type DateRangeValue = z.infer<typeof DateRangeValueSchema>;\n\nexport const FilterOptionsSchema = z\n .object({\n static: z.array(z.object({ label: z.string(), value: JsonPrimitiveSchema })).optional(),\n dataSource: IdSchema.optional(),\n labelKey: DataPathSchema.optional(),\n valueKey: DataPathSchema.optional(),\n })\n .passthrough()\n .refine((o) => (o.static !== undefined) !== (o.dataSource !== undefined), {\n message: \"Provide exactly one of options.static or options.dataSource\",\n });\nexport type FilterOptions = z.infer<typeof FilterOptionsSchema>;\n\nconst base = {\n id: IdSchema,\n label: z.string().min(1),\n /** Not shown in the filter bar; set by widgets (e.g. clicking a stage tile). */\n hidden: z.boolean().optional(),\n};\n\nexport const DateRangeFilterSchema = z.object({ ...base, type: z.literal(\"dateRange\"), default: DateRangeValueSchema.optional(), presets: z.array(DatePresetSchema).optional() }).passthrough();\nexport const SelectFilterSchema = z\n .object({\n ...base,\n type: z.literal(\"select\"),\n default: JsonPrimitiveSchema.optional(),\n options: FilterOptionsSchema,\n clearable: z.boolean().optional(),\n /** Text shown when nothing is selected, e.g. \"All\" → \"Line (All)\". */\n allLabel: z.string().optional(),\n /** Show ← → arrows that step through the options. */\n stepper: z.boolean().optional(),\n })\n .passthrough();\nexport const MultiSelectFilterSchema = z.object({ ...base, type: z.literal(\"multiSelect\"), default: z.array(JsonPrimitiveSchema).optional(), options: FilterOptionsSchema, allLabel: z.string().optional() }).passthrough();\nexport const SearchFilterSchema = z.object({ ...base, type: z.literal(\"search\"), default: z.string().optional(), debounceMs: z.number().int().min(0).max(5000).optional() }).passthrough();\nexport const ToggleFilterSchema = z.object({ ...base, type: z.literal(\"toggle\"), default: z.boolean().optional() }).passthrough();\n\nexport const FilterDefSchema = z.discriminatedUnion(\"type\", [\n DateRangeFilterSchema,\n SelectFilterSchema,\n MultiSelectFilterSchema,\n SearchFilterSchema,\n ToggleFilterSchema,\n]);\nexport type FilterDef = z.infer<typeof FilterDefSchema>;\nexport type FilterType = FilterDef[\"type\"];\nexport const FILTER_TYPES: FilterType[] = [\"dateRange\", \"select\", \"multiSelect\", \"search\", \"toggle\"];\n","import { z } from \"zod\";\nimport { IdSchema } from \"./primitives\";\nimport { ParamValueSchema } from \"./refs\";\n\nexport const TransformStepSchema = z.union([\n z.string().min(1),\n z.object({ name: z.string().min(1), args: z.record(ParamValueSchema).optional() }).strict(),\n]);\nexport type TransformStep = z.infer<typeof TransformStepSchema>;\n\nexport const HttpRequestSchema = z\n .object({\n url: z.string().min(1).refine((u) => !/^\\s*(javascript|data|vbscript):/i.test(u), \"Unsafe URL scheme\"),\n method: z.enum([\"GET\", \"POST\"]).optional(),\n params: z.record(ParamValueSchema).optional(),\n body: ParamValueSchema.optional(),\n })\n .passthrough();\nexport type HttpRequestDef = z.infer<typeof HttpRequestSchema>;\n\nexport const HttpDataSourceSchema = z\n .object({\n id: IdSchema,\n kind: z.literal(\"http\"),\n request: HttpRequestSchema,\n transform: z.array(TransformStepSchema).optional(),\n refreshIntervalSec: z.number().int().min(5).optional(),\n })\n .passthrough();\nexport const StaticDataSourceSchema = z\n .object({\n id: IdSchema,\n kind: z.literal(\"static\"),\n static: z.unknown(),\n transform: z.array(TransformStepSchema).optional(),\n })\n .passthrough();\n\nexport const DataSourceDefSchema = z.discriminatedUnion(\"kind\", [HttpDataSourceSchema, StaticDataSourceSchema]);\nexport type DataSourceDef = z.infer<typeof DataSourceDefSchema>;\nexport type HttpDataSourceDef = z.infer<typeof HttpDataSourceSchema>;\nexport type StaticDataSourceDef = z.infer<typeof StaticDataSourceSchema>;\n","import { z } from \"zod\";\nimport { JsonPrimitiveSchema, type JsonPrimitive } from \"./primitives\";\nimport { RefSchema, type Ref } from \"./refs\";\n\nexport type Condition =\n | { op: \"eq\" | \"neq\" | \"gt\" | \"gte\" | \"lt\" | \"lte\"; left: Ref; right: Ref | JsonPrimitive }\n | { op: \"in\" | \"nin\"; left: Ref; right: JsonPrimitive[] }\n | { op: \"empty\" | \"notEmpty\"; left: Ref }\n | { op: \"and\" | \"or\"; conditions: Condition[] }\n | { op: \"not\"; condition: Condition };\n\nexport const ConditionSchema: z.ZodType<Condition> = z.lazy(() =>\n z.union([\n z.object({ op: z.enum([\"eq\", \"neq\", \"gt\", \"gte\", \"lt\", \"lte\"]), left: RefSchema, right: z.union([RefSchema, JsonPrimitiveSchema]) }).strict(),\n z.object({ op: z.enum([\"in\", \"nin\"]), left: RefSchema, right: z.array(JsonPrimitiveSchema) }).strict(),\n z.object({ op: z.enum([\"empty\", \"notEmpty\"]), left: RefSchema }).strict(),\n z.object({ op: z.enum([\"and\", \"or\"]), conditions: z.array(ConditionSchema).min(1) }).strict(),\n z.object({ op: z.literal(\"not\"), condition: ConditionSchema }).strict(),\n ]),\n);\n\nexport const MAX_CONDITION_DEPTH = 5;\nexport function conditionDepth(c: Condition): number {\n if (\"conditions\" in c) return 1 + Math.max(...c.conditions.map(conditionDepth));\n if (\"condition\" in c) return 1 + conditionDepth(c.condition);\n return 1;\n}\n","import { z } from \"zod\";\nimport { IdSchema } from \"./primitives\";\nimport { ActionValueSchema } from \"./refs\";\n\nexport const TriggerSchema = z.enum([\"click\", \"rowClick\"]);\nexport type Trigger = z.infer<typeof TriggerSchema>;\n\nconst vars = z.record(ActionValueSchema).optional();\n\nexport const NavigateActionSchema = z.object({ on: TriggerSchema, type: z.literal(\"navigate\"), params: z.object({ to: z.string().min(1), query: vars }).passthrough() }).passthrough();\nexport const SetFilterActionSchema = z.object({ on: TriggerSchema, type: z.literal(\"setFilter\"), params: z.object({ filter: IdSchema, value: ActionValueSchema }).passthrough() }).passthrough();\nexport const DrilldownActionSchema = z.object({ on: TriggerSchema, type: z.literal(\"drilldown\"), params: z.object({ dashboardId: IdSchema, variables: vars }).passthrough() }).passthrough();\nexport const OpenModalActionSchema = z.object({ on: TriggerSchema, type: z.literal(\"openModal\"), params: z.object({ widget: IdSchema, title: z.string().optional(), variables: vars }).passthrough() }).passthrough();\n\nexport const ActionDefSchema = z.discriminatedUnion(\"type\", [NavigateActionSchema, SetFilterActionSchema, DrilldownActionSchema, OpenModalActionSchema]);\nexport type ActionDef = z.infer<typeof ActionDefSchema>;\nexport type ActionType = ActionDef[\"type\"];\n","import { z } from \"zod\";\nimport { ActionDefSchema } from \"./actions\";\nimport { ConditionSchema } from \"./conditions\";\nimport { DataPathSchema, IdSchema } from \"./primitives\";\n\nconst int = z.number().int();\nexport const GridPosSchema = z\n .object({ x: int.min(0).max(11), y: int.min(0), w: int.min(1).max(12), h: int.min(1), minW: int.min(1).max(12).optional(), minH: int.min(1).optional() })\n .passthrough();\nexport type GridPos = z.infer<typeof GridPosSchema>;\n\nexport const WidgetLayoutSchema = GridPosSchema.extend({\n responsive: z.object({ md: GridPosSchema.optional(), sm: GridPosSchema.optional(), xs: GridPosSchema.optional() }).optional(),\n}).passthrough();\nexport type WidgetLayout = z.infer<typeof WidgetLayoutSchema>;\n\nexport const WidgetDefSchema = z\n .object({\n id: IdSchema,\n type: z.string().min(1),\n title: z.string().optional(),\n subtitle: z.string().optional(),\n /** Text for the ⓘ tooltip next to the title. */\n info: z.string().max(2000).optional(),\n /** Short text on the right of the header, e.g. \"Total: 20 heats\". */\n meta: z.string().max(200).optional(),\n /** Show a \"Live · updated just now\" badge (refreshes with the data). */\n live: z.boolean().optional(),\n layout: WidgetLayoutSchema,\n dataSource: IdSchema.optional(),\n mapping: z.record(DataPathSchema).optional(),\n options: z.record(z.unknown()).optional(),\n listensTo: z.array(IdSchema).optional(),\n actions: z.array(ActionDefSchema).optional(),\n visibleWhen: ConditionSchema.optional(),\n })\n .passthrough();\nexport type WidgetDef = z.infer<typeof WidgetDefSchema>;\n","import { z } from \"zod\";\nimport { DataSourceDefSchema } from \"./dataSources\";\nimport { FilterDefSchema } from \"./filters\";\nimport { IdSchema } from \"./primitives\";\nimport { WidgetDefSchema } from \"./widgets\";\n\nexport const CURRENT_SCHEMA_VERSION = 1 as const;\n\nexport const LayoutDefSchema = z\n .object({\n columns: z.literal(12),\n rowHeight: z.number().int().min(20).max(200),\n breakpoints: z.object({ lg: z.number().int().min(0).optional(), md: z.number().int().min(0).optional(), sm: z.number().int().min(0).optional(), xs: z.number().int().min(0).optional() }).optional(),\n /** Horizontal gap between cards, px (default 16). */\n gapX: z.number().int().min(0).max(48).optional(),\n /** Vertical gap between rows, px (default 16). */\n gapY: z.number().int().min(0).max(48).optional(),\n /** \"grid\": every card is h × rowHeight. \"content\": each row is as tall as its tallest card; charts use h × rowHeight. */\n fit: z.enum([\"grid\", \"content\"]).optional(),\n /** Show the dashboard title/description above the filters (default true). */\n showHeader: z.boolean().optional(),\n })\n .passthrough();\nexport type LayoutDef = z.infer<typeof LayoutDefSchema>;\n\nexport const DashboardMetaSchema = z\n .object({ createdBy: z.string().optional(), updatedAt: z.string().optional(), tags: z.array(z.string()).optional() })\n .passthrough();\n\nexport const DashboardSchemaV1 = z\n .object({\n schemaVersion: z.literal(1),\n id: IdSchema,\n title: z.string().min(1),\n description: z.string().optional(),\n layout: LayoutDefSchema,\n filters: z.array(FilterDefSchema).default([]),\n dataSources: z.array(DataSourceDefSchema).default([]),\n widgets: z.array(WidgetDefSchema).default([]),\n meta: DashboardMetaSchema.optional(),\n })\n .passthrough();\n\n/** The parsed dashboard (defaults applied). */\nexport type DashboardSchema = z.output<typeof DashboardSchemaV1>;\n/** What an author may write (arrays optional). */\nexport type DashboardSchemaInput = z.input<typeof DashboardSchemaV1>;\n","import { CURRENT_SCHEMA_VERSION } from \"../dashboard\";\n\nexport type Migration = (input: Record<string, unknown>) => Record<string, unknown>;\n\n/**\n * migrations[n] upgrades a document from version n to n + 1.\n * Add `v1_to_v2.ts` here when schema v2 exists; never edit an existing migration.\n */\nexport const migrations: Record<number, Migration> = {};\n\nexport class MigrationError extends Error {\n override name = \"MigrationError\";\n}\n\nconst isObject = (v: unknown): v is Record<string, unknown> => typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/** Upgrades any known older document to the current schema version. Pure: never mutates input. */\nexport function migrateSchema(input: unknown): unknown {\n if (!isObject(input)) throw new MigrationError(\"Dashboard JSON must be an object\");\n const raw = input.schemaVersion;\n if (raw === undefined) throw new MigrationError(\"Missing 'schemaVersion'\");\n if (typeof raw !== \"number\" || !Number.isInteger(raw) || raw < 1) throw new MigrationError(`Invalid schemaVersion: ${JSON.stringify(raw)}`);\n if (raw > CURRENT_SCHEMA_VERSION) {\n throw new MigrationError(`Dashboard uses schemaVersion ${raw}, but this renderer supports up to ${CURRENT_SCHEMA_VERSION}. Upgrade the renderer package.`);\n }\n let doc: Record<string, unknown> = structuredClone(input);\n for (let v = raw; v < CURRENT_SCHEMA_VERSION; v++) {\n const step = migrations[v];\n if (!step) throw new MigrationError(`No migration registered from v${v} to v${v + 1}`);\n doc = { ...step(doc), schemaVersion: v + 1 };\n }\n return doc;\n}\n","import type { ZodIssue } from \"zod\";\nimport type { Condition } from \"./conditions\";\nimport { conditionDepth, MAX_CONDITION_DEPTH } from \"./conditions\";\nimport { DashboardSchemaV1, type DashboardSchema } from \"./dashboard\";\nimport { migrateSchema, MigrationError } from \"./migrations\";\nimport { isFilterRef } from \"./refs\";\n\nexport interface SchemaIssue {\n /** e.g. \"widgets[3].dataSource\" */\n path: string;\n message: string;\n}\nexport type ValidationResult =\n | { ok: true; data: DashboardSchema; errors: []; warnings: SchemaIssue[] }\n | { ok: false; data?: undefined; errors: SchemaIssue[]; warnings: SchemaIssue[] };\n\nexport function formatPath(path: ReadonlyArray<string | number>): string {\n return path.reduce<string>((acc, seg) => (typeof seg === \"number\" ? `${acc}[${seg}]` : acc ? `${acc}.${seg}` : seg), \"\");\n}\n\nconst fromZod = (i: ZodIssue): SchemaIssue => ({ path: formatPath(i.path), message: i.message });\n\nconst KNOWN_KEYS: Record<string, readonly string[]> = {\n root: [\"schemaVersion\", \"id\", \"title\", \"description\", \"layout\", \"filters\", \"dataSources\", \"widgets\", \"meta\"],\n widget: [\"id\", \"type\", \"title\", \"subtitle\", \"info\", \"meta\", \"live\", \"layout\", \"dataSource\", \"mapping\", \"options\", \"listensTo\", \"actions\", \"visibleWhen\"],\n};\n\nfunction collectRefs(value: unknown, out: string[]): void {\n if (Array.isArray(value)) value.forEach((v) => collectRefs(v, out));\n else if (isFilterRef(value)) out.push(value.$filter.split(\".\")[0] as string);\n else if (typeof value === \"object\" && value !== null) Object.values(value).forEach((v) => collectRefs(v, out));\n}\n\nfunction conditionRefs(c: Condition, out: string[]): void {\n if (\"conditions\" in c) c.conditions.forEach((x) => conditionRefs(x, out));\n else if (\"condition\" in c) conditionRefs(c.condition, out);\n else collectRefs([c.left, \"right\" in c ? c.right : null], out);\n}\n\n/** Checks that zod cannot express: unique ids, references that resolve, grid bounds, cycles. */\nexport function crossValidate(d: DashboardSchema): { errors: SchemaIssue[]; warnings: SchemaIssue[] } {\n const errors: SchemaIssue[] = [];\n const warnings: SchemaIssue[] = [];\n\n const dupes = (items: { id: string }[], key: string) => {\n const seen = new Set<string>();\n items.forEach((it, i) => {\n if (seen.has(it.id)) errors.push({ path: `${key}[${i}].id`, message: `Duplicate id '${it.id}'` });\n seen.add(it.id);\n });\n };\n dupes(d.widgets, \"widgets\");\n dupes(d.filters, \"filters\");\n dupes(d.dataSources, \"dataSources\");\n\n const filterIds = new Set(d.filters.map((f) => f.id));\n const dsIds = new Set(d.dataSources.map((s) => s.id));\n const widgetIds = new Set(d.widgets.map((w) => w.id));\n const checkFilterRefs = (value: unknown, path: string) => {\n const refs: string[] = [];\n collectRefs(value, refs);\n refs.forEach((r) => !filterIds.has(r) && errors.push({ path, message: `Unknown filter '${r}' in $filter reference` }));\n };\n\n // Data sources: filter refs and dependency cycles (filter options → data source → filter …).\n d.dataSources.forEach((s, i) => {\n if (s.kind === \"http\") checkFilterRefs(s.request, `dataSources[${i}].request`);\n s.transform?.forEach((t, j) => typeof t !== \"string\" && checkFilterRefs(t.args, `dataSources[${i}].transform[${j}]`));\n });\n\n d.filters.forEach((f, i) => {\n if ((f.type === \"select\" || f.type === \"multiSelect\") && f.options.dataSource && !dsIds.has(f.options.dataSource)) {\n errors.push({ path: `filters[${i}].options.dataSource`, message: `Unknown data source '${f.options.dataSource}'` });\n }\n });\n\n // Cycle: filter F's options come from source S, and S depends on F (directly or via other filters).\n const sourceDeps = new Map<string, string[]>();\n d.dataSources.forEach((s) => {\n const refs: string[] = [];\n if (s.kind === \"http\") collectRefs(s.request, refs);\n sourceDeps.set(s.id, refs);\n });\n const filterSource = new Map<string, string>();\n d.filters.forEach((f) => (f.type === \"select\" || f.type === \"multiSelect\") && f.options.dataSource && filterSource.set(f.id, f.options.dataSource));\n const visit = (filterId: string, stack: Set<string>): boolean => {\n if (stack.has(filterId)) return true;\n const src = filterSource.get(filterId);\n if (!src) return false;\n stack.add(filterId);\n const cyc = (sourceDeps.get(src) ?? []).some((f) => visit(f, stack));\n stack.delete(filterId);\n return cyc;\n };\n d.filters.forEach((f, i) => visit(f.id, new Set()) && errors.push({ path: `filters[${i}].options.dataSource`, message: `Filter '${f.id}' options depend on itself (cycle)` }));\n\n d.widgets.forEach((w, i) => {\n const p = `widgets[${i}]`;\n if (w.dataSource && !dsIds.has(w.dataSource)) errors.push({ path: `${p}.dataSource`, message: `Unknown data source '${w.dataSource}'` });\n if (w.layout.x + w.layout.w > 12) errors.push({ path: `${p}.layout`, message: `Widget overflows the 12-column grid (x + w = ${w.layout.x + w.layout.w})` });\n w.listensTo?.forEach((f, j) => !filterIds.has(f) && errors.push({ path: `${p}.listensTo[${j}]`, message: `Unknown filter '${f}'` }));\n if (w.visibleWhen) {\n if (conditionDepth(w.visibleWhen) > MAX_CONDITION_DEPTH) errors.push({ path: `${p}.visibleWhen`, message: `Condition nesting deeper than ${MAX_CONDITION_DEPTH}` });\n const refs: string[] = [];\n conditionRefs(w.visibleWhen, refs);\n refs.forEach((r) => !filterIds.has(r) && errors.push({ path: `${p}.visibleWhen`, message: `Unknown filter '${r}'` }));\n }\n w.actions?.forEach((a, j) => {\n const ap = `${p}.actions[${j}].params`;\n if (a.type === \"setFilter\" && !filterIds.has(a.params.filter)) errors.push({ path: `${ap}.filter`, message: `Unknown filter '${a.params.filter}'` });\n if (a.type === \"openModal\" && !widgetIds.has(a.params.widget)) errors.push({ path: `${ap}.widget`, message: `Unknown widget '${a.params.widget}'` });\n checkFilterRefs(a.params, ap);\n });\n Object.keys(w).forEach((k) => !KNOWN_KEYS.widget!.includes(k) && warnings.push({ path: `${p}.${k}`, message: `Unknown field '${k}' (kept, ignored by v1 renderer)` }));\n });\n\n Object.keys(d).forEach((k) => !KNOWN_KEYS.root!.includes(k) && warnings.push({ path: k, message: `Unknown field '${k}' (kept, ignored by v1 renderer)` }));\n return { errors, warnings };\n}\n\n/**\n * Migrates (if needed) and validates a dashboard document.\n * Never throws: always returns a result object.\n */\nexport function validateSchema(json: unknown): ValidationResult {\n let migrated: unknown;\n try {\n migrated = migrateSchema(json);\n } catch (e) {\n const message = e instanceof MigrationError ? e.message : \"Could not read dashboard JSON\";\n return { ok: false, errors: [{ path: \"schemaVersion\", message }], warnings: [] };\n }\n const parsed = DashboardSchemaV1.safeParse(migrated);\n if (!parsed.success) return { ok: false, errors: parsed.error.issues.map(fromZod), warnings: [] };\n const { errors, warnings } = crossValidate(parsed.data);\n if (errors.length) return { ok: false, errors, warnings };\n return { ok: true, data: parsed.data, errors: [], warnings };\n}\n\n/** Parses a JSON string, then validates. */\nexport function validateJsonString(text: string): ValidationResult {\n try {\n return validateSchema(JSON.parse(text));\n } catch (e) {\n return { ok: false, errors: [{ path: \"\", message: e instanceof Error ? e.message : \"Invalid JSON\" }], warnings: [] };\n }\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z","z","z","z","z","z"]}
package/package.json CHANGED
@@ -1,6 +1,57 @@
1
1
  {
2
2
  "name": "@metalcloud/dashboard-schema",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.3.0",
4
+ "description": "Dashboard JSON schema v1: zod schemas, TypeScript types, validation, migrations and JSON Schema.",
5
+ "keywords": [
6
+ "dashboard",
7
+ "schema",
8
+ "zod",
9
+ "json-schema"
10
+ ],
11
+ "license": "UNLICENSED",
12
+ "author": "NowPurchase / MetalCloud",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/NowPurchase/JSON-Dashboard-Builder.git",
16
+ "directory": "packages/schema"
17
+ },
18
+ "type": "module",
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js",
26
+ "require": "./dist/index.cjs"
27
+ },
28
+ "./dashboard.schema.json": "./dist/dashboard.schema.json"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md"
33
+ ],
34
+ "sideEffects": false,
35
+ "engines": {
36
+ "node": ">=18"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "dependencies": {
42
+ "zod": "^3.25.76"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^22",
46
+ "tsup": "^8.3.5",
47
+ "tsx": "^4.19.2",
48
+ "typescript": "^5.7.2",
49
+ "vitest": "^2.1.8",
50
+ "zod-to-json-schema": "^3.24.1"
51
+ },
52
+ "scripts": {
53
+ "build": "tsup && tsx scripts/gen-json-schema.ts",
54
+ "test": "vitest run",
55
+ "typecheck": "tsc --noEmit"
56
+ }
6
57
  }