@xpert-ai/plugin-live-dashboard 0.4.0 → 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.
- package/.xpertai-plugin/plugin.json +1 -1
- package/README.md +4 -0
- package/dist/lib/agent.schema.d.ts +179 -25
- package/dist/lib/agent.schema.js +10 -9
- package/dist/lib/archive.service.d.ts +145 -0
- package/dist/lib/archive.service.js +133 -0
- package/dist/lib/content.provider.d.ts +1 -1
- package/dist/lib/dashboard-archive.d.ts +70 -0
- package/dist/lib/dashboard-archive.js +118 -0
- package/dist/lib/dashboard-sources.d.ts +69 -0
- package/dist/lib/dashboard-sources.js +37 -0
- package/dist/lib/dashboard-view.schema.d.ts +503 -88
- package/dist/lib/dashboard-view.schema.js +2 -1
- package/dist/lib/dashboard.schema.d.ts +379 -58
- package/dist/lib/dashboard.schema.js +18 -1
- package/dist/lib/dashboard.service.d.ts +72 -17
- package/dist/lib/dashboard.service.js +21 -3
- package/dist/lib/document-package.d.ts +19 -4
- package/dist/lib/editing-patch.d.ts +3 -0
- package/dist/lib/editing-patch.js +2 -1
- package/dist/lib/editing-session.d.ts +4 -4
- package/dist/lib/editing.d.ts +202 -19
- package/dist/lib/editing.js +5 -2
- package/dist/lib/html-validation-feedback.d.ts +7 -0
- package/dist/lib/html-validation-feedback.js +19 -0
- package/dist/lib/html-validation.js +2 -1
- package/dist/lib/inspection-host.d.ts +7 -0
- package/dist/lib/inspection-host.js +48 -0
- package/dist/lib/inspection-runtime.d.ts +2 -0
- package/dist/lib/inspection-runtime.js +77 -0
- package/dist/lib/json-input.d.ts +4 -0
- package/dist/lib/json-input.js +21 -0
- package/dist/lib/middleware.js +3 -2
- package/dist/lib/plugin.js +2 -1
- package/dist/lib/presentation.provider.d.ts +24 -9
- package/dist/lib/presentation.provider.js +2 -1
- package/dist/lib/projects.schema.d.ts +14 -0
- package/dist/lib/projects.schema.js +2 -1
- package/dist/lib/projects.service.d.ts +2 -0
- package/dist/lib/projects.service.js +10 -0
- package/dist/lib/source-executions.d.ts +196 -0
- package/dist/lib/source-executions.js +25 -0
- package/dist/lib/source-validation.d.ts +2 -0
- package/dist/lib/source-validation.js +21 -0
- package/dist/lib/view.provider.d.ts +211 -12
- package/dist/lib/view.provider.js +43 -9
- package/dist/remote/app.css +1 -1
- package/dist/remote/app.js +99 -26
- package/dist/remote/build-manifest.json +42 -27
- package/docs/docs.json +3 -1
- package/docs/sources-inspect-portability-acceptance.mdx +67 -0
- package/docs/sources-inspect-portability.mdx +115 -0
- package/package.json +6 -5
- package/skills/live-dashboard/SKILL.md +5 -4
- 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
|
+
}
|
package/dist/lib/middleware.js
CHANGED
|
@@ -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(
|
|
255
|
-
name: 'dashboard_preview_binding', description: 'Preview a complete canonical AnalyticsBinding returned by another tool. Serialize the complete
|
|
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
|
}),
|
package/dist/lib/plugin.js
CHANGED
|
@@ -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);
|
|
@@ -9,6 +9,20 @@ export declare const projectSearchSchema: z.ZodObject<{
|
|
|
9
9
|
search?: string | undefined;
|
|
10
10
|
page?: number | undefined;
|
|
11
11
|
}>;
|
|
12
|
+
export declare const dashboardSearchSchema: z.ZodObject<{
|
|
13
|
+
search: z.ZodDefault<z.ZodString>;
|
|
14
|
+
page: z.ZodDefault<z.ZodNumber>;
|
|
15
|
+
} & {
|
|
16
|
+
projectId: z.ZodOptional<z.ZodString>;
|
|
17
|
+
}, "strict", z.ZodTypeAny, {
|
|
18
|
+
search: string;
|
|
19
|
+
page: number;
|
|
20
|
+
projectId?: string | undefined;
|
|
21
|
+
}, {
|
|
22
|
+
search?: string | undefined;
|
|
23
|
+
page?: number | undefined;
|
|
24
|
+
projectId?: string | undefined;
|
|
25
|
+
}>;
|
|
12
26
|
export declare const dashboardProjectSchema: z.ZodObject<{
|
|
13
27
|
id: z.ZodString;
|
|
14
28
|
name: z.ZodString;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.dashboardProjectsSchema = exports.dashboardProjectSchema = exports.projectSearchSchema = void 0;
|
|
3
|
+
exports.dashboardProjectsSchema = exports.dashboardProjectSchema = exports.dashboardSearchSchema = exports.projectSearchSchema = void 0;
|
|
4
4
|
const v3_1 = require("zod/v3");
|
|
5
5
|
exports.projectSearchSchema = v3_1.z.object({ search: v3_1.z.string().trim().max(200).default(''), page: v3_1.z.number().int().positive().default(1) }).strict();
|
|
6
|
+
exports.dashboardSearchSchema = exports.projectSearchSchema.extend({ projectId: v3_1.z.string().uuid().optional() });
|
|
6
7
|
exports.dashboardProjectSchema = v3_1.z.object({ id: v3_1.z.string().uuid(), name: v3_1.z.string() });
|
|
7
8
|
exports.dashboardProjectsSchema = v3_1.z.object({ items: v3_1.z.array(exports.dashboardProjectSchema), page: v3_1.z.number().int().positive(), hasMore: v3_1.z.boolean() });
|
|
@@ -12,6 +12,8 @@ export declare class DashboardProjectsService {
|
|
|
12
12
|
id: string;
|
|
13
13
|
name: string;
|
|
14
14
|
} | null>;
|
|
15
|
+
/** A picker target is untrusted until membership and the Assistant binding are revalidated. */
|
|
16
|
+
pickerContext(context: XpertResolvedViewHostContext, targetProjectId: string): Promise<XpertResolvedViewHostContext>;
|
|
15
17
|
list(context: XpertResolvedViewHostContext, input: z.infer<typeof projectSearchSchema>): Promise<{
|
|
16
18
|
items: {
|
|
17
19
|
id: string;
|
|
@@ -35,6 +35,16 @@ let DashboardProjectsService = class DashboardProjectsService {
|
|
|
35
35
|
const access = await this.runtime.require(plugin_sdk_1.ProjectAccessRuntimeCapability).assertAssistant({ actor: this.actor(context), projectId: id, assistantId: context.hostId });
|
|
36
36
|
return { id, name: access.name ?? id };
|
|
37
37
|
}
|
|
38
|
+
/** A picker target is untrusted until membership and the Assistant binding are revalidated. */
|
|
39
|
+
async pickerContext(context, targetProjectId) {
|
|
40
|
+
const access = await this.runtime.require(plugin_sdk_1.ProjectAccessRuntimeCapability).assertAssistant({
|
|
41
|
+
actor: this.actor(context), projectId: targetProjectId, assistantId: context.hostId
|
|
42
|
+
});
|
|
43
|
+
if (access.archived || access.projectId !== targetProjectId)
|
|
44
|
+
throw new common_1.ForbiddenException('DASHBOARD_ACCESS_DENIED');
|
|
45
|
+
// Domain reads/deletes accept a Project host. Do not fabricate file/conversation grants.
|
|
46
|
+
return { ...context, hostType: 'project', hostId: access.projectId, runtimeScope: undefined };
|
|
47
|
+
}
|
|
38
48
|
async list(context, input) {
|
|
39
49
|
const actor = this.actor(context), access = this.runtime.require(plugin_sdk_1.ProjectAccessRuntimeCapability);
|
|
40
50
|
const projects = await access.listReadable({ actor });
|
|
@@ -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,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
|
+
}
|