@xpert-ai/plugin-live-dashboard 0.5.0 → 0.6.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 -2
- package/dist/index.js +3 -1
- package/dist/lib/agent.schema.d.ts +9 -9
- package/dist/lib/agent.schema.js +2 -1
- package/dist/lib/archive.service.d.ts +26 -2
- package/dist/lib/archive.service.js +17 -3
- package/dist/lib/bounded-map.d.ts +2 -0
- package/dist/lib/bounded-map.js +25 -0
- package/dist/lib/capacity.d.ts +14 -0
- package/dist/lib/capacity.js +16 -0
- package/dist/lib/dashboard-archive.d.ts +1 -1
- package/dist/lib/dashboard-queries.d.ts +1 -1
- package/dist/lib/dashboard-queries.js +11 -6
- package/dist/lib/dashboard-receipt.js +1 -1
- package/dist/lib/dashboard-sources.js +3 -2
- package/dist/lib/dashboard-view.schema.d.ts +20 -20
- package/dist/lib/dashboard.schema.d.ts +18 -18
- package/dist/lib/dashboard.schema.js +2 -1
- package/dist/lib/dashboard.service.d.ts +24 -5
- package/dist/lib/dashboard.service.js +58 -8
- package/dist/lib/definition-tools.d.ts +4 -4
- package/dist/lib/document-host.js +1 -1
- package/dist/lib/document-package.d.ts +1 -1
- package/dist/lib/editing-patch.js +2 -1
- package/dist/lib/editing.d.ts +11 -10
- package/dist/lib/editing.js +5 -1
- package/dist/lib/filter-evidence.d.ts +28 -0
- package/dist/lib/filter-evidence.js +3 -2
- package/dist/lib/html-guidance.d.ts +1 -0
- package/dist/lib/html-guidance.js +2 -1
- package/dist/lib/html-validation.js +1 -1
- package/dist/lib/middleware.d.ts +3 -1
- package/dist/lib/middleware.js +89 -11
- package/dist/lib/plugin.js +2 -1
- package/dist/lib/presentation.provider.d.ts +1 -1
- package/dist/lib/preview-retry.d.ts +4 -3
- package/dist/lib/preview-retry.js +13 -7
- package/dist/lib/prompt-workflows.js +1 -1
- package/dist/lib/query-session.d.ts +9 -0
- package/dist/lib/query-session.js +64 -0
- package/dist/lib/save-requests.d.ts +118 -0
- package/dist/lib/save-requests.js +199 -0
- package/dist/lib/source-executions.d.ts +243 -2
- package/dist/lib/source-executions.js +29 -5
- package/dist/lib/view.provider.d.ts +38 -3
- package/dist/lib/view.provider.js +20 -4
- package/dist/remote/app.js +114 -65
- package/dist/remote/build-manifest.json +37 -32
- package/dist/sandbox-actions/action.json +1 -1
- package/dist/sandbox-actions/bundle/host.js +63 -14
- package/dist/sandbox-actions/bundle/validate.mjs +2 -2
- package/dist/validation/host-entry.d.ts +5 -1
- package/dist/validation/host-entry.js +21 -4
- package/docs/docs.json +2 -0
- package/docs/large-dashboards-acceptance.mdx +74 -0
- package/docs/large-dashboards.mdx +80 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@ Sources, component Inspect and portable dashboard archives are tracked in the
|
|
|
8
8
|
[feature guide](docs/sources-inspect-portability.mdx) and
|
|
9
9
|
[current acceptance record](docs/sources-inspect-portability-acceptance.mdx).
|
|
10
10
|
|
|
11
|
+
Large dashboards now support 32 Bindings by default (64 protocol ceiling), bounded query scheduling, batch preview/filter validation and durable save progress. See the [feature guide](docs/large-dashboards.mdx) and [acceptance record](docs/large-dashboards-acceptance.mdx). These features require published SDK/contracts 3.33.0 or later; no SDK patch is required.
|
|
12
|
+
|
|
11
13
|
## Ownership and flow
|
|
12
14
|
|
|
13
15
|
```text
|
|
@@ -194,7 +196,7 @@ See [HTML mode and acceptance](docs/html-mode.md). Agent tools write a complete
|
|
|
194
196
|
|
|
195
197
|
The platform browser entry `@xpert-ai/plugin-sdk/artifact-document` owns the sandbox, CSP, MessageChannel, request validation and latest-response policy. The plugin owns lifecycle and supplies a narrow callback to `query-binding`. Its server loads the exact saved Artifact version, finds the declared Binding, validates controls and rechecks source access. The endpoint rejects full Binding, Provider, SQL/payload and alternate source fields.
|
|
196
198
|
|
|
197
|
-
HTML preflight checks each native select's alternative/restored values and each button path in a fresh document mount, with at most two pages active. A button path also clicks controls it inserts, reveals or enables, retaining their prerequisite state and the same query quota; traversal is bounded to the first 12 buttons and 12 clicks per path. Every scenario checks initial bindings and host refresh using the same preview datasets. Successful static resources can be reused within this validation (bounded to 32 MB, up to 8 MB per resource); every replay still passes the resource policy, and failed, redirected or non-cacheable responses are not replayed. A 55-second validation deadline fails closed and cancels remaining pages before the host's 60-second Action limit. This prevents repeated resource downloads and the synthetic interaction sweep from exhausting the Action budget or one document's rate window
|
|
199
|
+
HTML preflight checks each native select's alternative/restored values and each button path in a fresh document mount, with at most two pages active. A button path also clicks controls it inserts, reveals or enables, retaining their prerequisite state and the same query quota; traversal is bounded to the first 12 buttons and 12 clicks per path. Every scenario checks initial bindings and host refresh using the same preview datasets. Successful static resources can be reused within this validation (bounded to 32 MB, up to 8 MB per resource); every replay still passes the resource policy, and failed, redirected or non-cacheable responses are not replayed. A 55-second validation deadline fails closed and cancels remaining pages before the host's 60-second Action limit. This prevents repeated resource downloads and the synthetic interaction sweep from exhausting the Action budget or one document's rate window with a separate immutable-snapshot budget of at most 16 replays per Binding; live queries remain limited to 60 dispatches per minute and concurrency 4. A request storm within a scenario still blocks saving; preflight is not a full combinatorial or sustained-load test.
|
|
198
200
|
|
|
199
201
|
Pages call `window.xpertLiveArtifact.ready()`, `subscribe(bindingId, render)`, `query(bindingId, controls)` and `refresh(bindingId)`. Register subscriptions before the first query so the toolbar can refresh without resetting the document. Use inline DOM/SVG/Canvas or online scripts/styles/fonts from the HTTPS origins returned by `dashboard_libraries.online`. Tailwind CDN, jsDelivr, cdnjs, unpkg and Google Fonts are supported according to their resource-type allowlist. Preflight and the displayed page use the same policy; failed loads prevent saving. Pin online versions where possible. Unlike packaged libraries, online bytes are not part of the immutable Artifact snapshot. Direct data requests, external images, eval, workers and frames remain unavailable. Script processing remains in the separate Workspace Script provider.
|
|
200
202
|
|
|
@@ -208,7 +210,7 @@ The renderer runs in a script-only sandbox with no-network CSP. A small in-memor
|
|
|
208
210
|
|
|
209
211
|
## Build and validation
|
|
210
212
|
|
|
211
|
-
Use the xpertai workspace's declared Corepack/pnpm. Development dependencies pin published SDK/contracts 3.
|
|
213
|
+
Use the xpertai workspace's declared Corepack/pnpm. Development dependencies pin published SDK/contracts 3.33.0 and the Data Analytics renderer 0.1.35; no local platform or community links are required. SDK 3.33.0 supplies the host-owned online resource policy, bounded query scheduler and grouped query runtime without a local SDK patch. Rebuild both the viewer and HTML preflight assets after changing the SDK; `verify:dist` checks their source fingerprints.
|
|
212
214
|
|
|
213
215
|
```sh
|
|
214
216
|
corepack pnpm install --frozen-lockfile
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const capacity_1 = require("./lib/capacity");
|
|
3
4
|
const node_fs_1 = require("node:fs");
|
|
4
5
|
const node_path_1 = require("node:path");
|
|
5
6
|
const plugin_1 = require("./lib/plugin");
|
|
@@ -18,7 +19,8 @@ const plugin = {
|
|
|
18
19
|
{ type: 'assistant-template', name: assistant_template_1.DASHBOARD_TEMPLATE_KEY, displayName: assistant_template_1.dashboardAssistantTemplate.title, description: assistant_template_1.dashboardAssistantTemplate.description }
|
|
19
20
|
] } } }
|
|
20
21
|
},
|
|
22
|
+
config: { schema: capacity_1.dashboardConfigSchema },
|
|
21
23
|
templates: templates_1.dashboardTemplates,
|
|
22
|
-
register:
|
|
24
|
+
register: context => ({ module: plugin_1.LiveDashboardPlugin, providers: [{ provide: capacity_1.DASHBOARD_CONFIG, useValue: capacity_1.dashboardConfigSchema.parse(context.config ?? {}) }] })
|
|
23
25
|
};
|
|
24
26
|
exports.default = plugin;
|
|
@@ -376,24 +376,24 @@ export declare const createToolSchema: z.ZodObject<{} & {
|
|
|
376
376
|
y: z.ZodString;
|
|
377
377
|
color: z.ZodOptional<z.ZodString>;
|
|
378
378
|
}, "strict", z.ZodTypeAny, {
|
|
379
|
-
title: string;
|
|
380
379
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
380
|
+
title: string;
|
|
381
381
|
id: string;
|
|
382
382
|
datasetId: string;
|
|
383
383
|
x: string;
|
|
384
384
|
y: string;
|
|
385
385
|
color?: string | undefined;
|
|
386
386
|
}, {
|
|
387
|
-
title: string;
|
|
388
387
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
388
|
+
title: string;
|
|
389
389
|
id: string;
|
|
390
390
|
datasetId: string;
|
|
391
391
|
x: string;
|
|
392
392
|
y: string;
|
|
393
393
|
color?: string | undefined;
|
|
394
394
|
}>, "many">, {
|
|
395
|
-
title: string;
|
|
396
395
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
396
|
+
title: string;
|
|
397
397
|
id: string;
|
|
398
398
|
datasetId: string;
|
|
399
399
|
x: string;
|
|
@@ -492,8 +492,8 @@ export declare const createToolSchema: z.ZodObject<{} & {
|
|
|
492
492
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
493
493
|
}[];
|
|
494
494
|
charts: {
|
|
495
|
-
title: string;
|
|
496
495
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
496
|
+
title: string;
|
|
497
497
|
id: string;
|
|
498
498
|
datasetId: string;
|
|
499
499
|
x: string;
|
|
@@ -575,24 +575,24 @@ export declare const createHtmlToolSchema: z.ZodObject<Omit<{} & {
|
|
|
575
575
|
y: z.ZodString;
|
|
576
576
|
color: z.ZodOptional<z.ZodString>;
|
|
577
577
|
}, "strict", z.ZodTypeAny, {
|
|
578
|
-
title: string;
|
|
579
578
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
579
|
+
title: string;
|
|
580
580
|
id: string;
|
|
581
581
|
datasetId: string;
|
|
582
582
|
x: string;
|
|
583
583
|
y: string;
|
|
584
584
|
color?: string | undefined;
|
|
585
585
|
}, {
|
|
586
|
-
title: string;
|
|
587
586
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
587
|
+
title: string;
|
|
588
588
|
id: string;
|
|
589
589
|
datasetId: string;
|
|
590
590
|
x: string;
|
|
591
591
|
y: string;
|
|
592
592
|
color?: string | undefined;
|
|
593
593
|
}>, "many">, {
|
|
594
|
-
title: string;
|
|
595
594
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
595
|
+
title: string;
|
|
596
596
|
id: string;
|
|
597
597
|
datasetId: string;
|
|
598
598
|
x: string;
|
|
@@ -685,8 +685,8 @@ export declare const createHtmlToolSchema: z.ZodObject<Omit<{} & {
|
|
|
685
685
|
path: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
|
|
686
686
|
libraries: z.ZodOptional<z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodEnum<["echarts", "three", "trend-workspace", "profit-atlas", "customer-brief"]>, "many">, ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[], ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[]>, ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[], ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[]>>;
|
|
687
687
|
}, "strict", z.ZodTypeAny, {
|
|
688
|
-
title: string;
|
|
689
688
|
path: string;
|
|
689
|
+
title: string;
|
|
690
690
|
controls: {
|
|
691
691
|
type: "string" | "number" | "boolean" | "date";
|
|
692
692
|
controlId: string;
|
|
@@ -714,8 +714,8 @@ export declare const createHtmlToolSchema: z.ZodObject<Omit<{} & {
|
|
|
714
714
|
supersedesPaths?: string[] | undefined;
|
|
715
715
|
libraries?: ("echarts" | "three" | "trend-workspace" | "profit-atlas" | "customer-brief")[] | undefined;
|
|
716
716
|
}, {
|
|
717
|
-
title: string;
|
|
718
717
|
path: string;
|
|
718
|
+
title: string;
|
|
719
719
|
sourceMetadata?: unknown;
|
|
720
720
|
components?: unknown;
|
|
721
721
|
controls?: unknown;
|
package/dist/lib/agent.schema.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createHtmlToolSchema = exports.htmlPathSchema = exports.createToolSchema = exports.previewToolSchema = exports.agentBindingSchema = exports.discoverToolSchema = void 0;
|
|
4
4
|
exports.parseObjectJson = parseObjectJson;
|
|
5
5
|
exports.fromAgentBinding = fromAgentBinding;
|
|
6
|
+
const capacity_1 = require("./capacity");
|
|
6
7
|
const v3_1 = require("zod/v3");
|
|
7
8
|
const analytics_1 = require("@xpert-ai/plugin-sdk/analytics");
|
|
8
9
|
const dashboard_schema_1 = require("./dashboard.schema");
|
|
@@ -31,7 +32,7 @@ exports.createToolSchema = dashboard_schema_1.dashboardSchema.innerType().omit({
|
|
|
31
32
|
tables: (0, plugin_sdk_1.jsonEncodedSchema)(dashboard_schema_1.dashboardSchema.innerType().shape.tables),
|
|
32
33
|
sourceMetadata: (0, plugin_sdk_1.jsonEncodedSchema)(dashboard_schema_1.dashboardSchema.innerType().shape.sourceMetadata.unwrap()).optional(),
|
|
33
34
|
components: (0, plugin_sdk_1.jsonEncodedSchema)(dashboard_schema_1.dashboardSchema.innerType().shape.components.unwrap()).optional(),
|
|
34
|
-
previewIds: (0, plugin_sdk_1.jsonEncodedSchema)(v3_1.z.array(v3_1.z.string().min(1)).min(1).max(
|
|
35
|
+
previewIds: (0, plugin_sdk_1.jsonEncodedSchema)(v3_1.z.array(v3_1.z.string().min(1)).min(1).max(capacity_1.MAX_DASHBOARD_BINDINGS).describe('Exact current-run previewId receipts from successful dashboard_preview or dashboard_preview_binding calls. For updates, changed bindings upsert by stable binding.id; omitted bindings remain. Keep every intended changed/new binding receipt when retrying a failed save. Do not repeat bindings.'))
|
|
35
36
|
}).strict();
|
|
36
37
|
exports.htmlPathSchema = plugin_sdk_1.workspaceRelativeFilePathSchema.refine(path => {
|
|
37
38
|
const name = path.split('/').at(-1) ?? '';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DashboardSaveRequests } from './save-requests';
|
|
1
2
|
import { z } from 'zod/v3';
|
|
2
3
|
import type { XpertResolvedViewHostContext } from '@xpert-ai/contracts';
|
|
3
4
|
import { type RuntimeCapabilityRegistry, type WorkspacePortableFileReference } from '@xpert-ai/plugin-sdk';
|
|
@@ -52,8 +53,9 @@ type ImportInput = z.infer<typeof importInputSchema>;
|
|
|
52
53
|
export declare class DashboardArchiveService {
|
|
53
54
|
private readonly dashboards;
|
|
54
55
|
private readonly runtime;
|
|
56
|
+
private readonly saves?;
|
|
55
57
|
private readonly imports;
|
|
56
|
-
constructor(dashboards: DashboardService, runtime: RuntimeCapabilityRegistry);
|
|
58
|
+
constructor(dashboards: DashboardService, runtime: RuntimeCapabilityRegistry, saves?: DashboardSaveRequests | undefined);
|
|
57
59
|
private authorize;
|
|
58
60
|
private session;
|
|
59
61
|
prepare(context: XpertResolvedViewHostContext, bytes: Buffer): Promise<{
|
|
@@ -71,8 +73,8 @@ export declare class DashboardArchiveService {
|
|
|
71
73
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
72
74
|
}[];
|
|
73
75
|
charts: {
|
|
74
|
-
title: string;
|
|
75
76
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
77
|
+
title: string;
|
|
76
78
|
id: string;
|
|
77
79
|
datasetId: string;
|
|
78
80
|
x: string;
|
|
@@ -131,6 +133,28 @@ export declare class DashboardArchiveService {
|
|
|
131
133
|
baseVersionId: string | null;
|
|
132
134
|
status: "draft";
|
|
133
135
|
title: string;
|
|
136
|
+
} | {
|
|
137
|
+
cursor: string;
|
|
138
|
+
nextAction: string;
|
|
139
|
+
error?: string | undefined;
|
|
140
|
+
sourceFile?: {
|
|
141
|
+
path: string;
|
|
142
|
+
sha256: string;
|
|
143
|
+
} | undefined;
|
|
144
|
+
dashboard?: {
|
|
145
|
+
status: "draft";
|
|
146
|
+
title: string;
|
|
147
|
+
artifactId: string;
|
|
148
|
+
draftRevision: number;
|
|
149
|
+
draftId: string;
|
|
150
|
+
baseVersionId: string | null;
|
|
151
|
+
} | undefined;
|
|
152
|
+
requestId: string;
|
|
153
|
+
state: "failed" | "running" | "succeeded" | "queued";
|
|
154
|
+
stage: string;
|
|
155
|
+
completed: number;
|
|
156
|
+
total: number;
|
|
157
|
+
terminal: boolean;
|
|
134
158
|
}>;
|
|
135
159
|
discard(context: XpertResolvedViewHostContext, id: string): Promise<{
|
|
136
160
|
discarded: boolean;
|
|
@@ -13,6 +13,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.importBrowseSchema = exports.DashboardArchiveService = exports.importInputSchema = void 0;
|
|
16
|
+
const save_requests_1 = require("./save-requests");
|
|
17
|
+
const capacity_1 = require("./capacity");
|
|
16
18
|
const common_1 = require("@nestjs/common");
|
|
17
19
|
const node_crypto_1 = require("node:crypto");
|
|
18
20
|
const v3_1 = require("zod/v3");
|
|
@@ -23,14 +25,15 @@ const dashboard_schema_1 = require("./dashboard.schema");
|
|
|
23
25
|
const dashboard_archive_1 = require("./dashboard-archive");
|
|
24
26
|
const document_package_1 = require("./document-package");
|
|
25
27
|
exports.importInputSchema = v3_1.z.object({ importId: v3_1.z.string().uuid(),
|
|
26
|
-
bindings: v3_1.z.array(v3_1.z.object({ bindingId: v3_1.z.string(), source: analytics_1.analyticsSourceRefSchema, payload: analytics_1.analyticsBindingObjectSchema.shape.payload }).strict()).max(
|
|
28
|
+
bindings: v3_1.z.array(v3_1.z.object({ bindingId: v3_1.z.string(), source: analytics_1.analyticsSourceRefSchema, payload: analytics_1.analyticsBindingObjectSchema.shape.payload }).strict()).max(capacity_1.MAX_DASHBOARD_BINDINGS)
|
|
27
29
|
}).strict();
|
|
28
30
|
const importBrowseSchema = v3_1.z.object({ importId: v3_1.z.string().uuid(), bindingId: v3_1.z.string(), source: analytics_1.analyticsSourceRefSchema, request: analytics_1.analyticsOptionsSchema.default({}) }).strict();
|
|
29
31
|
exports.importBrowseSchema = importBrowseSchema;
|
|
30
32
|
let DashboardArchiveService = class DashboardArchiveService {
|
|
31
|
-
constructor(dashboards, runtime) {
|
|
33
|
+
constructor(dashboards, runtime, saves) {
|
|
32
34
|
this.dashboards = dashboards;
|
|
33
35
|
this.runtime = runtime;
|
|
36
|
+
this.saves = saves;
|
|
34
37
|
this.imports = new Map();
|
|
35
38
|
}
|
|
36
39
|
async authorize(context) {
|
|
@@ -76,6 +79,11 @@ let DashboardArchiveService = class DashboardArchiveService {
|
|
|
76
79
|
return replacement ? { ...binding, source: replacement.source, payload: replacement.payload } : binding;
|
|
77
80
|
}) });
|
|
78
81
|
const hash = (0, node_crypto_1.createHash)('sha256').update((0, document_package_1.encodeDashboardPackage)(manifest, session.dependencies)).digest('hex');
|
|
82
|
+
if (session.submitted && this.saves) {
|
|
83
|
+
if (session.submitted.hash !== hash)
|
|
84
|
+
throw new common_1.BadRequestException('DASHBOARD_IMPORT_ALREADY_SUBMITTED');
|
|
85
|
+
return this.saves.get(context, session.submitted.requestId);
|
|
86
|
+
}
|
|
79
87
|
if (session.committed) {
|
|
80
88
|
if (session.committed.hash !== hash)
|
|
81
89
|
throw new common_1.BadRequestException('DASHBOARD_IMPORT_ALREADY_COMPLETED');
|
|
@@ -85,6 +93,11 @@ let DashboardArchiveService = class DashboardArchiveService {
|
|
|
85
93
|
}
|
|
86
94
|
session.busy = true;
|
|
87
95
|
try {
|
|
96
|
+
if (this.saves && manifest.bindings.length > 8) {
|
|
97
|
+
const request = await this.saves.submit(context, manifest, null, 0, `import/${input.importId}/${hash}`, undefined, session.dependencies);
|
|
98
|
+
session.submitted = { hash, requestId: request.requestId };
|
|
99
|
+
return request;
|
|
100
|
+
}
|
|
88
101
|
const receipt = await this.dashboards.save(context, manifest, null, 0, session.dependencies);
|
|
89
102
|
session.committed = { hash, receipt };
|
|
90
103
|
return receipt;
|
|
@@ -126,7 +139,8 @@ exports.DashboardArchiveService = DashboardArchiveService;
|
|
|
126
139
|
exports.DashboardArchiveService = DashboardArchiveService = __decorate([
|
|
127
140
|
(0, common_1.Injectable)(),
|
|
128
141
|
__param(1, (0, common_1.Inject)(plugin_sdk_1.XPERT_RUNTIME_CAPABILITIES_TOKEN)),
|
|
129
|
-
|
|
142
|
+
__param(2, (0, common_1.Optional)()),
|
|
143
|
+
__metadata("design:paramtypes", [dashboard_service_1.DashboardService, Object, save_requests_1.DashboardSaveRequests])
|
|
130
144
|
], DashboardArchiveService);
|
|
131
145
|
function importScope(context) {
|
|
132
146
|
return JSON.stringify([context.tenantId, context.organizationId, context.userId, context.hostType, context.hostId, (0, dashboard_service_1.projectId)(context)]);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.boundedMap = boundedMap;
|
|
4
|
+
/** Drain every started task before returning; never exceed the worker budget on rejection. */
|
|
5
|
+
async function boundedMap(items, run, concurrency = 4) {
|
|
6
|
+
const results = new Array(items.length);
|
|
7
|
+
let next = 0, failed = false, failure;
|
|
8
|
+
await Promise.all(Array.from({ length: Math.min(Math.max(1, Math.min(8, concurrency)), items.length) }, async () => {
|
|
9
|
+
while (!failed && next < items.length) {
|
|
10
|
+
const index = next++;
|
|
11
|
+
try {
|
|
12
|
+
results[index] = await run(items[index], index);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (!failed) {
|
|
16
|
+
failed = true;
|
|
17
|
+
failure = error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}));
|
|
22
|
+
if (failed)
|
|
23
|
+
throw failure;
|
|
24
|
+
return results;
|
|
25
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from 'zod/v3';
|
|
2
|
+
/** Storage compatibility is independent of the administrator's authoring policy. */
|
|
3
|
+
export declare const MAX_DASHBOARD_BINDINGS = 64;
|
|
4
|
+
export declare const DEFAULT_DASHBOARD_BINDINGS = 32;
|
|
5
|
+
export declare const DASHBOARD_CONFIG = "live-dashboard.config";
|
|
6
|
+
export declare const dashboardConfigSchema: z.ZodDefault<z.ZodObject<{
|
|
7
|
+
maxBindings: z.ZodDefault<z.ZodNumber>;
|
|
8
|
+
}, "strict", z.ZodTypeAny, {
|
|
9
|
+
maxBindings: number;
|
|
10
|
+
}, {
|
|
11
|
+
maxBindings?: number | undefined;
|
|
12
|
+
}>>;
|
|
13
|
+
export type DashboardConfig = z.infer<typeof dashboardConfigSchema>;
|
|
14
|
+
export declare function assertBindingCapacity(count: number, previousCount?: number, limit?: number): void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dashboardConfigSchema = exports.DASHBOARD_CONFIG = exports.DEFAULT_DASHBOARD_BINDINGS = exports.MAX_DASHBOARD_BINDINGS = void 0;
|
|
4
|
+
exports.assertBindingCapacity = assertBindingCapacity;
|
|
5
|
+
const v3_1 = require("zod/v3");
|
|
6
|
+
/** Storage compatibility is independent of the administrator's authoring policy. */
|
|
7
|
+
exports.MAX_DASHBOARD_BINDINGS = 64;
|
|
8
|
+
exports.DEFAULT_DASHBOARD_BINDINGS = 32;
|
|
9
|
+
exports.DASHBOARD_CONFIG = 'live-dashboard.config';
|
|
10
|
+
exports.dashboardConfigSchema = v3_1.z.object({
|
|
11
|
+
maxBindings: v3_1.z.number().int().min(1).max(exports.MAX_DASHBOARD_BINDINGS).default(exports.DEFAULT_DASHBOARD_BINDINGS)
|
|
12
|
+
}).strict().default({});
|
|
13
|
+
function assertBindingCapacity(count, previousCount = 0, limit = exports.DEFAULT_DASHBOARD_BINDINGS) {
|
|
14
|
+
if (count > exports.MAX_DASHBOARD_BINDINGS || count > limit && count > previousCount)
|
|
15
|
+
throw new Error(`DASHBOARD_BINDING_CAPACITY: ${count} bindings; authoring limit ${limit}, storage limit ${exports.MAX_DASHBOARD_BINDINGS}. Reuse existing queries or increase the installation policy.`);
|
|
16
|
+
}
|
|
@@ -31,8 +31,8 @@ export declare function decodeDashboardArchive(bytes: Buffer): {
|
|
|
31
31
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
32
32
|
}[];
|
|
33
33
|
charts: {
|
|
34
|
-
title: string;
|
|
35
34
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
35
|
+
title: string;
|
|
36
36
|
id: string;
|
|
37
37
|
datasetId: string;
|
|
38
38
|
x: string;
|
|
@@ -5,7 +5,7 @@ export declare function validateControls(manifest: DashboardManifest, input: Rec
|
|
|
5
5
|
[x: string]: AnalyticsValue;
|
|
6
6
|
};
|
|
7
7
|
export declare function queryDashboardBinding(runtime: RuntimeCapabilityRegistry, actor: DataSourceActor, manifest: DashboardManifest, bindingId: string, input: Record<string, AnalyticsValue>): Promise<AnalyticalDataset>;
|
|
8
|
-
export declare function queryDashboard(runtime: RuntimeCapabilityRegistry, actor: DataSourceActor, manifest: DashboardManifest, input: Record<string, AnalyticsValue>): Promise<AnalyticalDataset[]>;
|
|
8
|
+
export declare function queryDashboard(runtime: RuntimeCapabilityRegistry, actor: DataSourceActor, manifest: DashboardManifest, input: Record<string, AnalyticsValue>, progress?: (completed: number) => Promise<void>): Promise<AnalyticalDataset[]>;
|
|
9
9
|
/** Read-only rendering can show independent successful bindings. Saving/publishing still
|
|
10
10
|
* uses queryDashboard and requires every binding to validate. Never return native error
|
|
11
11
|
* details, which may contain private source configuration or query text. */
|
|
@@ -4,6 +4,7 @@ exports.validateControls = validateControls;
|
|
|
4
4
|
exports.queryDashboardBinding = queryDashboardBinding;
|
|
5
5
|
exports.queryDashboard = queryDashboard;
|
|
6
6
|
exports.queryDashboardPartial = queryDashboardPartial;
|
|
7
|
+
const bounded_map_1 = require("./bounded-map");
|
|
7
8
|
const common_1 = require("@nestjs/common");
|
|
8
9
|
const plugin_sdk_1 = require("@xpert-ai/plugin-sdk");
|
|
9
10
|
function validateControls(manifest, input) {
|
|
@@ -29,11 +30,15 @@ async function queryDashboardBinding(runtime, actor, manifest, bindingId, input)
|
|
|
29
30
|
const selected = Object.fromEntries(Object.entries(controls).filter(([id]) => binding.parameters.some(parameter => parameter.controlId === id)));
|
|
30
31
|
return runtime.require(plugin_sdk_1.AnalyticsRuntimeCapability).query(actor, { binding, controls: selected });
|
|
31
32
|
}
|
|
32
|
-
async function queryDashboard(runtime, actor, manifest, input) {
|
|
33
|
+
async function queryDashboard(runtime, actor, manifest, input, progress) {
|
|
33
34
|
validateControls(manifest, input);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
let completed = 0;
|
|
36
|
+
const datasets = await (0, bounded_map_1.boundedMap)(manifest.bindings, async (binding) => {
|
|
37
|
+
await progress?.(completed);
|
|
38
|
+
const result = await queryDashboardBinding(runtime, actor, manifest, binding.id, input);
|
|
39
|
+
await progress?.(++completed);
|
|
40
|
+
return result;
|
|
41
|
+
});
|
|
37
42
|
if (Buffer.byteLength(JSON.stringify(datasets)) > 3_000_000)
|
|
38
43
|
throw new common_1.BadRequestException('DASHBOARD_RESULT_TOO_LARGE');
|
|
39
44
|
return datasets;
|
|
@@ -45,14 +50,14 @@ async function queryDashboardPartial(runtime, actor, manifest, input) {
|
|
|
45
50
|
validateControls(manifest, input);
|
|
46
51
|
const datasets = [];
|
|
47
52
|
const failures = [];
|
|
48
|
-
|
|
53
|
+
await (0, bounded_map_1.boundedMap)(manifest.bindings, async (binding) => {
|
|
49
54
|
try {
|
|
50
55
|
datasets.push(await queryDashboardBinding(runtime, actor, manifest, binding.id, input));
|
|
51
56
|
}
|
|
52
57
|
catch {
|
|
53
58
|
failures.push({ bindingId: binding.id, datasetId: binding.output.datasetId, reason: 'unavailable' });
|
|
54
59
|
}
|
|
55
|
-
}
|
|
60
|
+
});
|
|
56
61
|
if (Buffer.byteLength(JSON.stringify(datasets)) > 3_000_000)
|
|
57
62
|
throw new common_1.BadRequestException('DASHBOARD_RESULT_TOO_LARGE');
|
|
58
63
|
return { datasets, failures };
|
|
@@ -4,7 +4,7 @@ exports.DASHBOARD_MUTATION_TOOLS = void 0;
|
|
|
4
4
|
exports.createdDashboard = createdDashboard;
|
|
5
5
|
exports.savedDashboardSource = savedDashboardSource;
|
|
6
6
|
const v3_1 = require("zod/v3");
|
|
7
|
-
exports.DASHBOARD_MUTATION_TOOLS = ['dashboard_create', 'dashboard_create_html', 'dashboard_update'];
|
|
7
|
+
exports.DASHBOARD_MUTATION_TOOLS = ['dashboard_create', 'dashboard_create_html', 'dashboard_update', 'dashboard_wait_request', 'dashboard_get_request'];
|
|
8
8
|
const receiptSchema = v3_1.z.object({ dashboard: v3_1.z.object({ artifactId: v3_1.z.string().uuid(), draftRevision: v3_1.z.number().int().positive(), status: v3_1.z.literal('draft') }) });
|
|
9
9
|
/** Tool start/failed logs can share the host event channel; only a saved receipt opens a View. */
|
|
10
10
|
function createdDashboard(output) {
|
|
@@ -4,15 +4,16 @@ exports.dashboardComponentsSchema = exports.sourceMetadataSchema = exports.compo
|
|
|
4
4
|
exports.dashboardComponents = dashboardComponents;
|
|
5
5
|
exports.dashboardSources = dashboardSources;
|
|
6
6
|
exports.publicDashboardManifest = publicDashboardManifest;
|
|
7
|
+
const capacity_1 = require("./capacity");
|
|
7
8
|
const v3_1 = require("zod/v3");
|
|
8
9
|
exports.componentId = v3_1.z.string().regex(/^[A-Za-z][A-Za-z0-9_.-]{0,79}$/);
|
|
9
10
|
exports.sourceMetadataSchema = v3_1.z.array(v3_1.z.object({
|
|
10
11
|
bindingId: exports.componentId, title: v3_1.z.string().min(1).max(160), description: v3_1.z.string().max(2000).optional()
|
|
11
|
-
}).strict()).max(
|
|
12
|
+
}).strict()).max(capacity_1.MAX_DASHBOARD_BINDINGS);
|
|
12
13
|
exports.dashboardComponentsSchema = v3_1.z.array(v3_1.z.object({
|
|
13
14
|
id: exports.componentId, elementId: exports.componentId, title: v3_1.z.string().min(1).max(160),
|
|
14
15
|
kind: v3_1.z.enum(['metric', 'chart', 'table', 'filter', 'text']),
|
|
15
|
-
sources: v3_1.z.array(v3_1.z.object({ bindingId: exports.componentId, fieldIds: v3_1.z.array(exports.componentId).max(80).optional() }).strict()).max(
|
|
16
|
+
sources: v3_1.z.array(v3_1.z.object({ bindingId: exports.componentId, fieldIds: v3_1.z.array(exports.componentId).max(80).optional() }).strict()).max(capacity_1.MAX_DASHBOARD_BINDINGS)
|
|
16
17
|
}).strict()).max(160);
|
|
17
18
|
function dashboardComponents(manifest) {
|
|
18
19
|
if (manifest.presentation)
|
|
@@ -239,16 +239,16 @@ export declare const dashboardSavedSchema: z.ZodObject<{
|
|
|
239
239
|
y: z.ZodString;
|
|
240
240
|
color: z.ZodOptional<z.ZodString>;
|
|
241
241
|
}, "strict", z.ZodTypeAny, {
|
|
242
|
-
title: string;
|
|
243
242
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
243
|
+
title: string;
|
|
244
244
|
id: string;
|
|
245
245
|
datasetId: string;
|
|
246
246
|
x: string;
|
|
247
247
|
y: string;
|
|
248
248
|
color?: string | undefined;
|
|
249
249
|
}, {
|
|
250
|
-
title: string;
|
|
251
250
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
251
|
+
title: string;
|
|
252
252
|
id: string;
|
|
253
253
|
datasetId: string;
|
|
254
254
|
x: string;
|
|
@@ -284,8 +284,8 @@ export declare const dashboardSavedSchema: z.ZodObject<{
|
|
|
284
284
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
285
285
|
}[];
|
|
286
286
|
charts: {
|
|
287
|
-
title: string;
|
|
288
287
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
288
|
+
title: string;
|
|
289
289
|
id: string;
|
|
290
290
|
datasetId: string;
|
|
291
291
|
x: string;
|
|
@@ -331,8 +331,8 @@ export declare const dashboardSavedSchema: z.ZodObject<{
|
|
|
331
331
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
332
332
|
}[];
|
|
333
333
|
charts: {
|
|
334
|
-
title: string;
|
|
335
334
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
335
|
+
title: string;
|
|
336
336
|
id: string;
|
|
337
337
|
datasetId: string;
|
|
338
338
|
x: string;
|
|
@@ -384,8 +384,8 @@ export declare const dashboardSavedSchema: z.ZodObject<{
|
|
|
384
384
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
385
385
|
}[];
|
|
386
386
|
charts: {
|
|
387
|
-
title: string;
|
|
388
387
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
388
|
+
title: string;
|
|
389
389
|
id: string;
|
|
390
390
|
datasetId: string;
|
|
391
391
|
x: string;
|
|
@@ -431,8 +431,8 @@ export declare const dashboardSavedSchema: z.ZodObject<{
|
|
|
431
431
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
432
432
|
}[];
|
|
433
433
|
charts: {
|
|
434
|
-
title: string;
|
|
435
434
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
435
|
+
title: string;
|
|
436
436
|
id: string;
|
|
437
437
|
datasetId: string;
|
|
438
438
|
x: string;
|
|
@@ -516,8 +516,8 @@ export declare const dashboardSavedSchema: z.ZodObject<{
|
|
|
516
516
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
517
517
|
}[];
|
|
518
518
|
charts: {
|
|
519
|
-
title: string;
|
|
520
519
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
520
|
+
title: string;
|
|
521
521
|
id: string;
|
|
522
522
|
datasetId: string;
|
|
523
523
|
x: string;
|
|
@@ -575,8 +575,8 @@ export declare const dashboardSavedSchema: z.ZodObject<{
|
|
|
575
575
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
576
576
|
}[];
|
|
577
577
|
charts: {
|
|
578
|
-
title: string;
|
|
579
578
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
579
|
+
title: string;
|
|
580
580
|
id: string;
|
|
581
581
|
datasetId: string;
|
|
582
582
|
x: string;
|
|
@@ -902,16 +902,16 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
|
|
|
902
902
|
y: z.ZodString;
|
|
903
903
|
color: z.ZodOptional<z.ZodString>;
|
|
904
904
|
}, "strict", z.ZodTypeAny, {
|
|
905
|
-
title: string;
|
|
906
905
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
906
|
+
title: string;
|
|
907
907
|
id: string;
|
|
908
908
|
datasetId: string;
|
|
909
909
|
x: string;
|
|
910
910
|
y: string;
|
|
911
911
|
color?: string | undefined;
|
|
912
912
|
}, {
|
|
913
|
-
title: string;
|
|
914
913
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
914
|
+
title: string;
|
|
915
915
|
id: string;
|
|
916
916
|
datasetId: string;
|
|
917
917
|
x: string;
|
|
@@ -947,8 +947,8 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
|
|
|
947
947
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
948
948
|
}[];
|
|
949
949
|
charts: {
|
|
950
|
-
title: string;
|
|
951
950
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
951
|
+
title: string;
|
|
952
952
|
id: string;
|
|
953
953
|
datasetId: string;
|
|
954
954
|
x: string;
|
|
@@ -994,8 +994,8 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
|
|
|
994
994
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
995
995
|
}[];
|
|
996
996
|
charts: {
|
|
997
|
-
title: string;
|
|
998
997
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
998
|
+
title: string;
|
|
999
999
|
id: string;
|
|
1000
1000
|
datasetId: string;
|
|
1001
1001
|
x: string;
|
|
@@ -1047,8 +1047,8 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
|
|
|
1047
1047
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
1048
1048
|
}[];
|
|
1049
1049
|
charts: {
|
|
1050
|
-
title: string;
|
|
1051
1050
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
1051
|
+
title: string;
|
|
1052
1052
|
id: string;
|
|
1053
1053
|
datasetId: string;
|
|
1054
1054
|
x: string;
|
|
@@ -1094,8 +1094,8 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
|
|
|
1094
1094
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
1095
1095
|
}[];
|
|
1096
1096
|
charts: {
|
|
1097
|
-
title: string;
|
|
1098
1097
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
1098
|
+
title: string;
|
|
1099
1099
|
id: string;
|
|
1100
1100
|
datasetId: string;
|
|
1101
1101
|
x: string;
|
|
@@ -1179,8 +1179,8 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
|
|
|
1179
1179
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
1180
1180
|
}[];
|
|
1181
1181
|
charts: {
|
|
1182
|
-
title: string;
|
|
1183
1182
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
1183
|
+
title: string;
|
|
1184
1184
|
id: string;
|
|
1185
1185
|
datasetId: string;
|
|
1186
1186
|
x: string;
|
|
@@ -1238,8 +1238,8 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
|
|
|
1238
1238
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
1239
1239
|
}[];
|
|
1240
1240
|
charts: {
|
|
1241
|
-
title: string;
|
|
1242
1241
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
1242
|
+
title: string;
|
|
1243
1243
|
id: string;
|
|
1244
1244
|
datasetId: string;
|
|
1245
1245
|
x: string;
|
|
@@ -1359,8 +1359,8 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
|
|
|
1359
1359
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
1360
1360
|
}[];
|
|
1361
1361
|
charts: {
|
|
1362
|
-
title: string;
|
|
1363
1362
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
1363
|
+
title: string;
|
|
1364
1364
|
id: string;
|
|
1365
1365
|
datasetId: string;
|
|
1366
1366
|
x: string;
|
|
@@ -1479,8 +1479,8 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
|
|
|
1479
1479
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
1480
1480
|
}[];
|
|
1481
1481
|
charts: {
|
|
1482
|
-
title: string;
|
|
1483
1482
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
1483
|
+
title: string;
|
|
1484
1484
|
id: string;
|
|
1485
1485
|
datasetId: string;
|
|
1486
1486
|
x: string;
|
|
@@ -1614,8 +1614,8 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
|
|
|
1614
1614
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
1615
1615
|
}[];
|
|
1616
1616
|
charts: {
|
|
1617
|
-
title: string;
|
|
1618
1617
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
1618
|
+
title: string;
|
|
1619
1619
|
id: string;
|
|
1620
1620
|
datasetId: string;
|
|
1621
1621
|
x: string;
|
|
@@ -1736,8 +1736,8 @@ export declare const dashboardViewDataSchema: z.ZodObject<{
|
|
|
1736
1736
|
allowedValues?: (string | number | boolean | null)[] | undefined;
|
|
1737
1737
|
}[];
|
|
1738
1738
|
charts: {
|
|
1739
|
-
title: string;
|
|
1740
1739
|
type: "bar" | "line" | "area" | "pie" | "scatter";
|
|
1740
|
+
title: string;
|
|
1741
1741
|
id: string;
|
|
1742
1742
|
datasetId: string;
|
|
1743
1743
|
x: string;
|