@xpert-ai/plugin-live-dashboard 0.4.1 → 0.5.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 (50) hide show
  1. package/.xpertai-plugin/plugin.json +1 -1
  2. package/README.md +4 -0
  3. package/dist/lib/agent.schema.d.ts +179 -25
  4. package/dist/lib/agent.schema.js +10 -9
  5. package/dist/lib/archive.service.d.ts +145 -0
  6. package/dist/lib/archive.service.js +133 -0
  7. package/dist/lib/content.provider.d.ts +1 -1
  8. package/dist/lib/dashboard-archive.d.ts +70 -0
  9. package/dist/lib/dashboard-archive.js +118 -0
  10. package/dist/lib/dashboard-sources.d.ts +69 -0
  11. package/dist/lib/dashboard-sources.js +37 -0
  12. package/dist/lib/dashboard-view.schema.d.ts +422 -88
  13. package/dist/lib/dashboard.schema.d.ts +379 -58
  14. package/dist/lib/dashboard.schema.js +18 -1
  15. package/dist/lib/dashboard.service.d.ts +60 -14
  16. package/dist/lib/dashboard.service.js +8 -2
  17. package/dist/lib/document-package.d.ts +19 -4
  18. package/dist/lib/editing-patch.d.ts +3 -0
  19. package/dist/lib/editing-patch.js +2 -1
  20. package/dist/lib/editing-session.d.ts +4 -4
  21. package/dist/lib/editing.d.ts +202 -19
  22. package/dist/lib/editing.js +5 -2
  23. package/dist/lib/html-validation-feedback.d.ts +7 -0
  24. package/dist/lib/html-validation-feedback.js +19 -0
  25. package/dist/lib/html-validation.js +2 -1
  26. package/dist/lib/inspection-host.d.ts +7 -0
  27. package/dist/lib/inspection-host.js +48 -0
  28. package/dist/lib/inspection-runtime.d.ts +2 -0
  29. package/dist/lib/inspection-runtime.js +77 -0
  30. package/dist/lib/json-input.d.ts +4 -0
  31. package/dist/lib/json-input.js +21 -0
  32. package/dist/lib/middleware.js +3 -2
  33. package/dist/lib/plugin.js +2 -1
  34. package/dist/lib/presentation.provider.d.ts +24 -9
  35. package/dist/lib/presentation.provider.js +2 -1
  36. package/dist/lib/source-executions.d.ts +196 -0
  37. package/dist/lib/source-executions.js +25 -0
  38. package/dist/lib/source-validation.d.ts +2 -0
  39. package/dist/lib/source-validation.js +21 -0
  40. package/dist/lib/view.provider.d.ts +178 -8
  41. package/dist/lib/view.provider.js +30 -4
  42. package/dist/remote/app.css +1 -1
  43. package/dist/remote/app.js +100 -27
  44. package/dist/remote/build-manifest.json +37 -23
  45. package/docs/docs.json +3 -1
  46. package/docs/sources-inspect-portability-acceptance.mdx +67 -0
  47. package/docs/sources-inspect-portability.mdx +115 -0
  48. package/package.json +6 -5
  49. package/skills/live-dashboard/SKILL.md +5 -4
  50. package/skills/live-dashboard/references/source-inspection.md +17 -0
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DASHBOARD_INSPECTION_RUNTIME = void 0;
4
+ /** Injected into the isolated dashboard only; it never reads or executes query definitions. */
5
+ exports.DASHBOARD_INSPECTION_RUNTIME = String.raw `
6
+ (() => {
7
+ const key = '__INSPECTION_SESSION__', channel = 'live-dashboard.inspection';
8
+ let enabled = false, standard = false, components = [], selected = null, overlay, previousFocus;
9
+ const tabs = new Map();
10
+ const post = (type, data = {}) => parent.postMessage({ channel, key, type, ...data }, '*');
11
+ function outline(element) {
12
+ selected = element;
13
+ if (!element || !enabled) { if (overlay) overlay.hidden = true; return; }
14
+ if (!overlay) {
15
+ overlay = document.createElement('div');
16
+ overlay.setAttribute('aria-hidden', 'true');
17
+ overlay.style.cssText = 'position:fixed;pointer-events:none;z-index:2147483647;border:2px solid #2563eb;background:rgba(37,99,235,.06);box-sizing:border-box';
18
+ document.documentElement.append(overlay);
19
+ }
20
+ const r = element.getBoundingClientRect();
21
+ Object.assign(overlay.style, { left:r.left+'px', top:r.top+'px', width:r.width+'px', height:r.height+'px' });
22
+ overlay.hidden = false;
23
+ }
24
+ function target(node) {
25
+ for (let element = node instanceof Element ? node : null; element; element = element.parentElement) {
26
+ if (components.some(c => c.elementId === (standard ? element.getAttribute('data-layout-block-id') : element.id))) return element;
27
+ }
28
+ return null;
29
+ }
30
+ function registerTargets() {
31
+ if (!enabled) return;
32
+ for (const component of components) {
33
+ const element = standard ? [...document.querySelectorAll('[data-layout-block-id]')].find(e => e.getAttribute('data-layout-block-id') === component.elementId) : document.getElementById(component.elementId);
34
+ if (element && !tabs.has(element)) { tabs.set(element, element.getAttribute('tabindex')); element.setAttribute('tabindex', '0'); }
35
+ }
36
+ }
37
+ new MutationObserver(registerTargets).observe(document, { childList:true, subtree:true });
38
+ function activate(value) {
39
+ if (value === enabled) return;
40
+ enabled = value;
41
+ if (enabled) {
42
+ previousFocus = document.activeElement;
43
+ registerTargets();
44
+ } else {
45
+ outline(null);
46
+ for (const [element, value] of tabs) value === null ? element.removeAttribute('tabindex') : element.setAttribute('tabindex', value);
47
+ tabs.clear();
48
+ if (previousFocus instanceof HTMLElement && previousFocus.isConnected) previousFocus.focus({ preventScroll:true });
49
+ }
50
+ }
51
+ function choose(event) {
52
+ if (!enabled) return;
53
+ event.preventDefault(); event.stopImmediatePropagation();
54
+ const element = target(event.target), component = components.find(c => c.elementId === (standard ? element?.getAttribute('data-layout-block-id') : element?.id));
55
+ outline(element);
56
+ post('selected', { componentId:component?.id ?? null });
57
+ }
58
+ window.addEventListener('message', event => {
59
+ const m = event.data;
60
+ if (event.source !== parent || !m || m.channel !== channel || m.key !== key) return;
61
+ if (m.type === 'mode') { components = m.components; standard = m.standard; activate(m.enabled === true); }
62
+ });
63
+ window.addEventListener('pointermove', e => { if (enabled) outline(target(e.target)); }, true);
64
+ window.addEventListener('focusin', e => { if (enabled) outline(target(e.target)); }, true);
65
+ for (const name of ['pointerdown', 'pointerup', 'mousedown', 'mouseup', 'dblclick']) window.addEventListener(name, e => {
66
+ if (enabled) { e.preventDefault(); e.stopImmediatePropagation(); }
67
+ }, true);
68
+ window.addEventListener('click', choose, true);
69
+ window.addEventListener('keydown', e => {
70
+ if (!enabled) return;
71
+ if (e.key === 'Escape') { e.preventDefault(); e.stopImmediatePropagation(); activate(false); post('exit'); }
72
+ else if (e.key === 'Enter' || e.key === ' ') choose(e);
73
+ }, true);
74
+ window.addEventListener('scroll', () => { if (enabled) outline(selected); }, true);
75
+ window.addEventListener('resize', () => { if (enabled) outline(selected); });
76
+ post('ready');
77
+ })();`;
@@ -0,0 +1,4 @@
1
+ type JsonInputField = 'requestJson' | 'binding.payloadJson' | 'bindingJson';
2
+ /** Report syntax locations without echoing query text or native errors containing input fragments. */
3
+ export declare function parseJsonInput(text: string, field: JsonInputField): unknown;
4
+ export {};
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseJsonInput = parseJsonInput;
4
+ /** Report syntax locations without echoing query text or native errors containing input fragments. */
5
+ function parseJsonInput(text, field) {
6
+ try {
7
+ return JSON.parse(text);
8
+ }
9
+ catch (error) {
10
+ if (!(error instanceof SyntaxError))
11
+ throw error;
12
+ const match = /\bat position (\d+)(?: \(line \d+ column \d+\))?$/.exec(error.message);
13
+ const offset = match ? Number(match[1]) : error.message === 'Unexpected end of JSON input' ? text.length : undefined;
14
+ if (offset === undefined || offset > text.length) {
15
+ throw new Error(`DASHBOARD_INVALID_JSON: ${field} contains invalid JSON; the parser did not provide a character position. Supply one complete JSON object without Markdown fences.`);
16
+ }
17
+ const lines = text.slice(0, offset).split(/\r\n|\r|\n/);
18
+ const character = offset === text.length ? 'end of input' : JSON.stringify(String.fromCodePoint(text.codePointAt(offset)));
19
+ throw new Error(`DASHBOARD_INVALID_JSON: ${field} has invalid JSON at offset ${offset} (0-based UTF-16), line ${lines.length}, column ${lines.at(-1).length + 1} (1-based); found ${character}. Check this position and the preceding JSON delimiter or value.`);
20
+ }
21
+ }
@@ -37,6 +37,7 @@ const resource_card_1 = require("./resource-card");
37
37
  const dashboard_icon_1 = require("./dashboard-icon");
38
38
  const preview_retry_1 = require("./preview-retry");
39
39
  const prompt_workflows_1 = require("./prompt-workflows");
40
+ const json_input_1 = require("./json-input");
40
41
  const middlewareOptionsSchema = v3_1.z.object({ allowedFinalProviders: v3_1.z.array(v3_1.z.string().min(1)).min(1).max(20).optional(),
41
42
  maxModelCalls: v3_1.z.number().int().min(1).max(64).default(24) }).strict().default({});
42
43
  const providerOptionSchema = {
@@ -251,8 +252,8 @@ let DashboardMiddleware = class DashboardMiddleware {
251
252
  return preview(binding);
252
253
  }, { name: 'dashboard_preview', description: 'Run one read-only binding using parameters[].defaultValue. Automatically discovers the source/provider query contract when absent in this run; use dashboard_discover to inspect business metadata or repair invalid queries. Returns validated Dataset fields, first 20 rows, full query completeness and audit. Required before create; changes to binding/defaults require another preview.',
253
254
  schema: agent_schema_1.previewToolSchema, verboseParsingErrors: true, metadata: { toolName: { en_US: 'Verify dashboard data', zh_Hans: '预览并验证看板数据' } } }),
254
- (0, tools_1.tool)(async ({ bindingJson }) => preview(plugin_sdk_1.analyticsBindingSchema.parse(JSON.parse(bindingJson))), {
255
- name: 'dashboard_preview_binding', description: 'Preview a complete canonical AnalyticsBinding returned by another tool. Serialize the complete canonical Binding (for example discovery items[].metadata.binding), including parameters[].controlId. bindingPayload is only the payload, not a Binding. If adding a parameter, include name, controlId, type, required and defaultValue. Do not convert it to the simplified dashboard_preview input. Automatically discovers the source/provider query contract when absent in this run; use dashboard_discover for business metadata. Returns the same previewId receipt for dashboard_create.',
255
+ (0, tools_1.tool)(async ({ bindingJson }) => preview(plugin_sdk_1.analyticsBindingSchema.parse((0, json_input_1.parseJsonInput)(bindingJson, 'bindingJson'))), {
256
+ name: 'dashboard_preview_binding', description: 'Preview a complete canonical AnalyticsBinding returned by another tool. When editing an existing dashboard, copy dashboard_open.bindings[], preserve binding.id and existing parameters[].controlId, and change only the requested query/parameters. Binding ID is independent of output.datasetId. Serialize the complete Binding (also supported: discovery items[].metadata.binding), including parameters[].controlId. bindingPayload is only the payload, not a Binding. If adding a parameter, include name, controlId, type, required and defaultValue. Do not convert it to the simplified dashboard_preview input, which derives binding.id from output.datasetId. Automatically discovers the source/provider query contract when absent in this run. Returns a current-run previewId for dashboard_create or dashboard_update; include every intended changed/new Binding receipt and matching controls in the same save.',
256
257
  schema: v3_1.z.object({ bindingJson: v3_1.z.string().min(2).max(200000) }).strict(), verboseParsingErrors: true,
257
258
  metadata: { toolName: { en_US: 'Verify registered dataset', zh_Hans: '验证已注册数据集' } }
258
259
  }),
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  };
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.LiveDashboardPlugin = void 0;
10
+ const archive_service_1 = require("./archive.service");
10
11
  const projects_service_1 = require("./projects.service");
11
12
  const content_capability_1 = require("./content-capability");
12
13
  const monitor_1 = require("./monitor");
@@ -24,5 +25,5 @@ let LiveDashboardPlugin = class LiveDashboardPlugin {
24
25
  };
25
26
  exports.LiveDashboardPlugin = LiveDashboardPlugin;
26
27
  exports.LiveDashboardPlugin = LiveDashboardPlugin = __decorate([
27
- (0, plugin_sdk_1.XpertServerPlugin)({ controllers: [provider_options_controller_1.DashboardProviderOptionsController], providers: [projects_service_1.DashboardProjectsService, monitor_1.DashboardMonitor, monitor_1.DashboardMonitorMiddleware, artifact_type_provider_1.DashboardArtifactType, content_capability_1.DashboardCapability, content_provider_1.DashboardContentProvider, content_provider_1.DashboardContentEditor, dashboard_service_1.DashboardService, view_provider_1.DashboardViewProvider, middleware_1.DashboardMiddleware, html_validation_1.HtmlDashboardValidation, presentation_provider_1.DashboardPresentationProvider, sharing_service_1.DashboardSharingService] })
28
+ (0, plugin_sdk_1.XpertServerPlugin)({ controllers: [provider_options_controller_1.DashboardProviderOptionsController], providers: [archive_service_1.DashboardArchiveService, projects_service_1.DashboardProjectsService, monitor_1.DashboardMonitor, monitor_1.DashboardMonitorMiddleware, artifact_type_provider_1.DashboardArtifactType, content_capability_1.DashboardCapability, content_provider_1.DashboardContentProvider, content_provider_1.DashboardContentEditor, dashboard_service_1.DashboardService, view_provider_1.DashboardViewProvider, middleware_1.DashboardMiddleware, html_validation_1.HtmlDashboardValidation, presentation_provider_1.DashboardPresentationProvider, sharing_service_1.DashboardSharingService] })
28
29
  ], LiveDashboardPlugin);
@@ -11,15 +11,10 @@ export declare class DashboardPresentationProvider implements IArtifactPresentat
11
11
  read(context: ArtifactPresentationContext): Promise<{
12
12
  meta: {
13
13
  saved: {
14
- artifactId: string;
15
- versionId: string;
16
- versionNumber: number;
17
- title: string;
18
- isDraft: boolean;
19
14
  manifest: {
20
- schema: "xpert.live-dashboard";
21
- id: string;
22
15
  title: string;
16
+ id: string;
17
+ schema: "xpert.live-dashboard";
23
18
  bindings: import("@xpert-ai/contracts").AnalyticsBinding[];
24
19
  controls: {
25
20
  type: "string" | "number" | "boolean" | "date";
@@ -29,26 +24,46 @@ export declare class DashboardPresentationProvider implements IArtifactPresentat
29
24
  allowedValues?: (string | number | boolean | null)[] | undefined;
30
25
  }[];
31
26
  charts: {
27
+ title: string;
32
28
  type: "bar" | "line" | "area" | "pie" | "scatter";
33
29
  id: string;
34
- title: string;
35
30
  datasetId: string;
36
31
  x: string;
37
32
  y: string;
38
33
  color?: string | undefined;
39
34
  }[];
40
35
  tables: {
41
- id: string;
42
36
  title: string;
37
+ id: string;
43
38
  datasetId: string;
44
39
  fields: string[];
45
40
  }[];
41
+ sourceMetadata?: {
42
+ bindingId: string;
43
+ title: string;
44
+ description?: string | undefined;
45
+ }[] | undefined;
46
+ components?: {
47
+ title: string;
48
+ id: string;
49
+ elementId: string;
50
+ kind: "filter" | "metric" | "chart" | "table" | "text";
51
+ sources: {
52
+ bindingId: string;
53
+ fieldIds?: string[] | undefined;
54
+ }[];
55
+ }[] | undefined;
46
56
  presentation?: {
47
57
  type: "html";
48
58
  html: string;
49
59
  dependencies?: import("@xpert-ai/plugin-sdk/artifact-document").ArtifactDocumentDependencyLock[] | undefined;
50
60
  } | undefined;
51
61
  };
62
+ artifactId: string;
63
+ versionId: string;
64
+ versionNumber: number;
65
+ title: string;
66
+ isDraft: boolean;
52
67
  dependencies: import("@xpert-ai/plugin-sdk/artifact-document").ArtifactDocumentDependencyAsset[];
53
68
  };
54
69
  dashboards: {
@@ -22,6 +22,7 @@ const remote_entry_1 = require("./remote-entry");
22
22
  const dashboard_schema_1 = require("./dashboard.schema");
23
23
  const dashboard_queries_1 = require("./dashboard-queries");
24
24
  const renderer_1 = require("./renderer");
25
+ const dashboard_sources_1 = require("./dashboard-sources");
25
26
  let DashboardPresentationProvider = class DashboardPresentationProvider {
26
27
  constructor(runtime) {
27
28
  this.runtime = runtime;
@@ -30,7 +31,7 @@ let DashboardPresentationProvider = class DashboardPresentationProvider {
30
31
  getEntry() { return (0, remote_entry_1.dashboardRemoteEntry)(true); }
31
32
  async read(context) {
32
33
  const saved = this.open(context);
33
- return { meta: { saved, dashboards: [{ artifactId: saved.artifactId, versionId: saved.versionId, title: saved.title }], sources: [], versions: [] } };
34
+ return { meta: { saved: { ...saved, manifest: (0, dashboard_sources_1.publicDashboardManifest)(saved.manifest) }, dashboards: [{ artifactId: saved.artifactId, versionId: saved.versionId, title: saved.title }], sources: [], versions: [] } };
34
35
  }
35
36
  async query(context, request) {
36
37
  const saved = this.open(context);
@@ -0,0 +1,196 @@
1
+ import { z } from 'zod/v3';
2
+ export declare const sourceDatasetSchema: z.ZodObject<{
3
+ schema: z.ZodLiteral<"xpert.analytics.dataset">;
4
+ datasetId: z.ZodString;
5
+ fields: z.ZodArray<z.ZodObject<{
6
+ id: z.ZodString;
7
+ label: z.ZodOptional<z.ZodString>;
8
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
9
+ id: z.ZodString;
10
+ label: z.ZodOptional<z.ZodString>;
11
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
12
+ id: z.ZodString;
13
+ label: z.ZodOptional<z.ZodString>;
14
+ }, z.ZodTypeAny, "passthrough">>, "many">;
15
+ rows: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, "many">;
16
+ completeness: z.ZodObject<{
17
+ truncated: z.ZodBoolean;
18
+ returnedRows: z.ZodNumber;
19
+ scope: z.ZodString;
20
+ totalAccuracy: z.ZodString;
21
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
22
+ truncated: z.ZodBoolean;
23
+ returnedRows: z.ZodNumber;
24
+ scope: z.ZodString;
25
+ totalAccuracy: z.ZodString;
26
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
27
+ truncated: z.ZodBoolean;
28
+ returnedRows: z.ZodNumber;
29
+ scope: z.ZodString;
30
+ totalAccuracy: z.ZodString;
31
+ }, z.ZodTypeAny, "passthrough">>;
32
+ freshness: z.ZodObject<{
33
+ sourceFetchedAt: z.ZodString;
34
+ executedAt: z.ZodOptional<z.ZodString>;
35
+ dataAsOf: z.ZodOptional<z.ZodString>;
36
+ }, "strip", z.ZodTypeAny, {
37
+ sourceFetchedAt: string;
38
+ executedAt?: string | undefined;
39
+ dataAsOf?: string | undefined;
40
+ }, {
41
+ sourceFetchedAt: string;
42
+ executedAt?: string | undefined;
43
+ dataAsOf?: string | undefined;
44
+ }>;
45
+ provenance: z.ZodObject<{
46
+ executionId: z.ZodString;
47
+ bindingId: z.ZodString;
48
+ providerId: z.ZodString;
49
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
50
+ executionId: z.ZodString;
51
+ bindingId: z.ZodString;
52
+ providerId: z.ZodString;
53
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
54
+ executionId: z.ZodString;
55
+ bindingId: z.ZodString;
56
+ providerId: z.ZodString;
57
+ }, z.ZodTypeAny, "passthrough">>;
58
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
59
+ schema: z.ZodLiteral<"xpert.analytics.dataset">;
60
+ datasetId: z.ZodString;
61
+ fields: z.ZodArray<z.ZodObject<{
62
+ id: z.ZodString;
63
+ label: z.ZodOptional<z.ZodString>;
64
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
65
+ id: z.ZodString;
66
+ label: z.ZodOptional<z.ZodString>;
67
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
68
+ id: z.ZodString;
69
+ label: z.ZodOptional<z.ZodString>;
70
+ }, z.ZodTypeAny, "passthrough">>, "many">;
71
+ rows: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, "many">;
72
+ completeness: z.ZodObject<{
73
+ truncated: z.ZodBoolean;
74
+ returnedRows: z.ZodNumber;
75
+ scope: z.ZodString;
76
+ totalAccuracy: z.ZodString;
77
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
78
+ truncated: z.ZodBoolean;
79
+ returnedRows: z.ZodNumber;
80
+ scope: z.ZodString;
81
+ totalAccuracy: z.ZodString;
82
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
83
+ truncated: z.ZodBoolean;
84
+ returnedRows: z.ZodNumber;
85
+ scope: z.ZodString;
86
+ totalAccuracy: z.ZodString;
87
+ }, z.ZodTypeAny, "passthrough">>;
88
+ freshness: z.ZodObject<{
89
+ sourceFetchedAt: z.ZodString;
90
+ executedAt: z.ZodOptional<z.ZodString>;
91
+ dataAsOf: z.ZodOptional<z.ZodString>;
92
+ }, "strip", z.ZodTypeAny, {
93
+ sourceFetchedAt: string;
94
+ executedAt?: string | undefined;
95
+ dataAsOf?: string | undefined;
96
+ }, {
97
+ sourceFetchedAt: string;
98
+ executedAt?: string | undefined;
99
+ dataAsOf?: string | undefined;
100
+ }>;
101
+ provenance: z.ZodObject<{
102
+ executionId: z.ZodString;
103
+ bindingId: z.ZodString;
104
+ providerId: z.ZodString;
105
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
106
+ executionId: z.ZodString;
107
+ bindingId: z.ZodString;
108
+ providerId: z.ZodString;
109
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
110
+ executionId: z.ZodString;
111
+ bindingId: z.ZodString;
112
+ providerId: z.ZodString;
113
+ }, z.ZodTypeAny, "passthrough">>;
114
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
115
+ schema: z.ZodLiteral<"xpert.analytics.dataset">;
116
+ datasetId: z.ZodString;
117
+ fields: z.ZodArray<z.ZodObject<{
118
+ id: z.ZodString;
119
+ label: z.ZodOptional<z.ZodString>;
120
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
121
+ id: z.ZodString;
122
+ label: z.ZodOptional<z.ZodString>;
123
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
124
+ id: z.ZodString;
125
+ label: z.ZodOptional<z.ZodString>;
126
+ }, z.ZodTypeAny, "passthrough">>, "many">;
127
+ rows: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, "many">;
128
+ completeness: z.ZodObject<{
129
+ truncated: z.ZodBoolean;
130
+ returnedRows: z.ZodNumber;
131
+ scope: z.ZodString;
132
+ totalAccuracy: z.ZodString;
133
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
134
+ truncated: z.ZodBoolean;
135
+ returnedRows: z.ZodNumber;
136
+ scope: z.ZodString;
137
+ totalAccuracy: z.ZodString;
138
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
139
+ truncated: z.ZodBoolean;
140
+ returnedRows: z.ZodNumber;
141
+ scope: z.ZodString;
142
+ totalAccuracy: z.ZodString;
143
+ }, z.ZodTypeAny, "passthrough">>;
144
+ freshness: z.ZodObject<{
145
+ sourceFetchedAt: z.ZodString;
146
+ executedAt: z.ZodOptional<z.ZodString>;
147
+ dataAsOf: z.ZodOptional<z.ZodString>;
148
+ }, "strip", z.ZodTypeAny, {
149
+ sourceFetchedAt: string;
150
+ executedAt?: string | undefined;
151
+ dataAsOf?: string | undefined;
152
+ }, {
153
+ sourceFetchedAt: string;
154
+ executedAt?: string | undefined;
155
+ dataAsOf?: string | undefined;
156
+ }>;
157
+ provenance: z.ZodObject<{
158
+ executionId: z.ZodString;
159
+ bindingId: z.ZodString;
160
+ providerId: z.ZodString;
161
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
162
+ executionId: z.ZodString;
163
+ bindingId: z.ZodString;
164
+ providerId: z.ZodString;
165
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
166
+ executionId: z.ZodString;
167
+ bindingId: z.ZodString;
168
+ providerId: z.ZodString;
169
+ }, z.ZodTypeAny, "passthrough">>;
170
+ }, z.ZodTypeAny, "passthrough">>;
171
+ export type SourceDataset = z.infer<typeof sourceDatasetSchema>;
172
+ export interface SourceExecution {
173
+ requestId: string;
174
+ state: 'running' | 'succeeded' | 'failed';
175
+ controls: Record<string, string | number | boolean | null>;
176
+ requestedAt: string;
177
+ finishedAt?: string;
178
+ result?: SourceDataset;
179
+ resultControls?: SourceExecution['controls'];
180
+ }
181
+ export type SourceEvent = {
182
+ bindingId: string;
183
+ requestId: string;
184
+ } & ({
185
+ type: 'start';
186
+ controls: SourceExecution['controls'];
187
+ at: string;
188
+ } | {
189
+ type: 'success';
190
+ result: SourceDataset;
191
+ at: string;
192
+ } | {
193
+ type: 'failure';
194
+ at: string;
195
+ });
196
+ export declare function reduceSourceExecutions(state: Record<string, SourceExecution>, event: SourceEvent): Record<string, SourceExecution>;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sourceDatasetSchema = void 0;
4
+ exports.reduceSourceExecutions = reduceSourceExecutions;
5
+ const v3_1 = require("zod/v3");
6
+ const scalar = v3_1.z.union([v3_1.z.string(), v3_1.z.number(), v3_1.z.boolean(), v3_1.z.null()]);
7
+ exports.sourceDatasetSchema = v3_1.z.object({
8
+ schema: v3_1.z.literal('xpert.analytics.dataset'), datasetId: v3_1.z.string(),
9
+ fields: v3_1.z.array(v3_1.z.object({ id: v3_1.z.string(), label: v3_1.z.string().optional() }).passthrough()), rows: v3_1.z.array(v3_1.z.record(scalar)),
10
+ completeness: v3_1.z.object({ truncated: v3_1.z.boolean(), returnedRows: v3_1.z.number(), scope: v3_1.z.string(), totalAccuracy: v3_1.z.string() }).passthrough(),
11
+ freshness: v3_1.z.object({ sourceFetchedAt: v3_1.z.string(), executedAt: v3_1.z.string().optional(), dataAsOf: v3_1.z.string().optional() }),
12
+ provenance: v3_1.z.object({ executionId: v3_1.z.string(), bindingId: v3_1.z.string(), providerId: v3_1.z.string() }).passthrough()
13
+ }).passthrough();
14
+ function reduceSourceExecutions(state, event) {
15
+ const previous = state[event.bindingId];
16
+ if (event.type === 'start')
17
+ return { ...state, [event.bindingId]: {
18
+ requestId: event.requestId, state: 'running', controls: event.controls, requestedAt: event.at,
19
+ result: previous?.result, resultControls: previous?.resultControls
20
+ } };
21
+ if (!previous || previous.requestId !== event.requestId)
22
+ return state;
23
+ return { ...state, [event.bindingId]: { ...previous, state: event.type === 'success' ? 'succeeded' : 'failed', finishedAt: event.at,
24
+ ...(event.type === 'success' ? { result: { ...event.result, rows: event.result.rows.slice(0, 50) }, resultControls: previous.controls } : {}) } };
25
+ }
@@ -0,0 +1,2 @@
1
+ import type { DashboardManifest } from './dashboard.schema';
2
+ export declare function assertComponentElements(manifest: DashboardManifest): void;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertComponentElements = assertComponentElements;
4
+ const parse5_1 = require("parse5");
5
+ function assertComponentElements(manifest) {
6
+ if (!manifest.presentation || !manifest.components?.length)
7
+ return;
8
+ const ids = new Map();
9
+ const visit = (node) => {
10
+ if ('attrs' in node)
11
+ for (const attr of node.attrs)
12
+ if (attr.name === 'id')
13
+ ids.set(attr.value, (ids.get(attr.value) ?? 0) + 1);
14
+ if ('childNodes' in node)
15
+ node.childNodes.forEach(visit);
16
+ };
17
+ visit((0, parse5_1.parse)(manifest.presentation.html));
18
+ for (const component of manifest.components)
19
+ if (ids.get(component.elementId) !== 1)
20
+ throw new Error(`DASHBOARD_COMPONENT_ELEMENT_INVALID: ${component.id}`);
21
+ }