@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.
Files changed (58) hide show
  1. package/.xpertai-plugin/plugin.json +1 -1
  2. package/README.md +4 -2
  3. package/dist/index.js +3 -1
  4. package/dist/lib/agent.schema.d.ts +9 -9
  5. package/dist/lib/agent.schema.js +2 -1
  6. package/dist/lib/archive.service.d.ts +26 -2
  7. package/dist/lib/archive.service.js +17 -3
  8. package/dist/lib/bounded-map.d.ts +2 -0
  9. package/dist/lib/bounded-map.js +25 -0
  10. package/dist/lib/capacity.d.ts +14 -0
  11. package/dist/lib/capacity.js +16 -0
  12. package/dist/lib/dashboard-archive.d.ts +1 -1
  13. package/dist/lib/dashboard-queries.d.ts +1 -1
  14. package/dist/lib/dashboard-queries.js +11 -6
  15. package/dist/lib/dashboard-receipt.js +1 -1
  16. package/dist/lib/dashboard-sources.js +3 -2
  17. package/dist/lib/dashboard-view.schema.d.ts +20 -20
  18. package/dist/lib/dashboard.schema.d.ts +18 -18
  19. package/dist/lib/dashboard.schema.js +2 -1
  20. package/dist/lib/dashboard.service.d.ts +24 -5
  21. package/dist/lib/dashboard.service.js +58 -8
  22. package/dist/lib/definition-tools.d.ts +4 -4
  23. package/dist/lib/document-host.js +1 -1
  24. package/dist/lib/document-package.d.ts +1 -1
  25. package/dist/lib/editing-patch.js +2 -1
  26. package/dist/lib/editing.d.ts +11 -10
  27. package/dist/lib/editing.js +5 -1
  28. package/dist/lib/filter-evidence.d.ts +28 -0
  29. package/dist/lib/filter-evidence.js +3 -2
  30. package/dist/lib/html-guidance.d.ts +1 -0
  31. package/dist/lib/html-guidance.js +2 -1
  32. package/dist/lib/html-validation.js +1 -1
  33. package/dist/lib/middleware.d.ts +3 -1
  34. package/dist/lib/middleware.js +89 -11
  35. package/dist/lib/plugin.js +2 -1
  36. package/dist/lib/presentation.provider.d.ts +1 -1
  37. package/dist/lib/preview-retry.d.ts +4 -3
  38. package/dist/lib/preview-retry.js +13 -7
  39. package/dist/lib/prompt-workflows.js +1 -1
  40. package/dist/lib/query-session.d.ts +9 -0
  41. package/dist/lib/query-session.js +64 -0
  42. package/dist/lib/save-requests.d.ts +118 -0
  43. package/dist/lib/save-requests.js +199 -0
  44. package/dist/lib/source-executions.d.ts +243 -2
  45. package/dist/lib/source-executions.js +29 -5
  46. package/dist/lib/view.provider.d.ts +38 -3
  47. package/dist/lib/view.provider.js +20 -4
  48. package/dist/remote/app.js +114 -65
  49. package/dist/remote/build-manifest.json +37 -32
  50. package/dist/sandbox-actions/action.json +1 -1
  51. package/dist/sandbox-actions/bundle/host.js +63 -14
  52. package/dist/sandbox-actions/bundle/validate.mjs +2 -2
  53. package/dist/validation/host-entry.d.ts +5 -1
  54. package/dist/validation/host-entry.js +21 -4
  55. package/docs/docs.json +2 -0
  56. package/docs/large-dashboards-acceptance.mdx +74 -0
  57. package/docs/large-dashboards.mdx +80 -0
  58. package/package.json +5 -5
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xpert-ai/plugin-live-dashboard",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "level": "system",
5
5
  "artifactNamespace": "live_dashboard",
6
6
  "sandboxActions": "./dist/sandbox-actions/action.json",
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 without raising the SDK's query/concurrency limits. A request storm within a scenario still blocks saving; preflight is not a full combinatorial or sustained-load test.
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.27.0 and the Data Analytics renderer 0.1.35; no local platform or community links are required. SDK 3.27.0 includes the host-owned online resource policy, so no SDK patch is required. Rebuild both the viewer and HTML preflight assets after changing the SDK; `verify:dist` checks their source fingerprints.
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: () => ({ module: plugin_1.LiveDashboardPlugin })
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;
@@ -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(8).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
+ 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(8)
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
- __metadata("design:paramtypes", [dashboard_service_1.DashboardService, Object])
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,2 @@
1
+ /** Drain every started task before returning; never exceed the worker budget on rejection. */
2
+ export declare function boundedMap<T, R>(items: readonly T[], run: (item: T, index: number) => Promise<R>, concurrency?: number): Promise<R[]>;
@@ -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
- const datasets = [];
35
- for (const binding of manifest.bindings)
36
- datasets.push(await queryDashboardBinding(runtime, actor, manifest, binding.id, input));
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
- for (const binding of manifest.bindings) {
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(8);
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(8)
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;