@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.
Files changed (55) hide show
  1. package/.xpertai-plugin/plugin.json +1 -1
  2. package/README.md +4 -0
  3. package/dist/lib/agent.schema.d.ts +179 -25
  4. package/dist/lib/agent.schema.js +10 -9
  5. package/dist/lib/archive.service.d.ts +145 -0
  6. package/dist/lib/archive.service.js +133 -0
  7. package/dist/lib/content.provider.d.ts +1 -1
  8. package/dist/lib/dashboard-archive.d.ts +70 -0
  9. package/dist/lib/dashboard-archive.js +118 -0
  10. package/dist/lib/dashboard-sources.d.ts +69 -0
  11. package/dist/lib/dashboard-sources.js +37 -0
  12. package/dist/lib/dashboard-view.schema.d.ts +503 -88
  13. package/dist/lib/dashboard-view.schema.js +2 -1
  14. package/dist/lib/dashboard.schema.d.ts +379 -58
  15. package/dist/lib/dashboard.schema.js +18 -1
  16. package/dist/lib/dashboard.service.d.ts +72 -17
  17. package/dist/lib/dashboard.service.js +21 -3
  18. package/dist/lib/document-package.d.ts +19 -4
  19. package/dist/lib/editing-patch.d.ts +3 -0
  20. package/dist/lib/editing-patch.js +2 -1
  21. package/dist/lib/editing-session.d.ts +4 -4
  22. package/dist/lib/editing.d.ts +202 -19
  23. package/dist/lib/editing.js +5 -2
  24. package/dist/lib/html-validation-feedback.d.ts +7 -0
  25. package/dist/lib/html-validation-feedback.js +19 -0
  26. package/dist/lib/html-validation.js +2 -1
  27. package/dist/lib/inspection-host.d.ts +7 -0
  28. package/dist/lib/inspection-host.js +48 -0
  29. package/dist/lib/inspection-runtime.d.ts +2 -0
  30. package/dist/lib/inspection-runtime.js +77 -0
  31. package/dist/lib/json-input.d.ts +4 -0
  32. package/dist/lib/json-input.js +21 -0
  33. package/dist/lib/middleware.js +3 -2
  34. package/dist/lib/plugin.js +2 -1
  35. package/dist/lib/presentation.provider.d.ts +24 -9
  36. package/dist/lib/presentation.provider.js +2 -1
  37. package/dist/lib/projects.schema.d.ts +14 -0
  38. package/dist/lib/projects.schema.js +2 -1
  39. package/dist/lib/projects.service.d.ts +2 -0
  40. package/dist/lib/projects.service.js +10 -0
  41. package/dist/lib/source-executions.d.ts +196 -0
  42. package/dist/lib/source-executions.js +25 -0
  43. package/dist/lib/source-validation.d.ts +2 -0
  44. package/dist/lib/source-validation.js +21 -0
  45. package/dist/lib/view.provider.d.ts +211 -12
  46. package/dist/lib/view.provider.js +43 -9
  47. package/dist/remote/app.css +1 -1
  48. package/dist/remote/app.js +99 -26
  49. package/dist/remote/build-manifest.json +42 -27
  50. package/docs/docs.json +3 -1
  51. package/docs/sources-inspect-portability-acceptance.mdx +67 -0
  52. package/docs/sources-inspect-portability.mdx +115 -0
  53. package/package.json +6 -5
  54. package/skills/live-dashboard/SKILL.md +5 -4
  55. package/skills/live-dashboard/references/source-inspection.md +17 -0
@@ -4,10 +4,13 @@ exports.queryBindingSchema = exports.querySchema = exports.saveSchema = exports.
4
4
  const v3_1 = require("zod/v3");
5
5
  const analytics_1 = require("@xpert-ai/plugin-sdk/analytics");
6
6
  const artifact_document_1 = require("@xpert-ai/plugin-sdk/artifact-document");
7
+ const dashboard_sources_1 = require("./dashboard-sources");
7
8
  const id = v3_1.z.string().regex(/^[A-Za-z][A-Za-z0-9_.-]{0,79}$/);
8
9
  exports.dashboardSchema = v3_1.z.object({
9
10
  schema: v3_1.z.literal('xpert.live-dashboard'), id: v3_1.z.string().uuid(), title: v3_1.z.string().min(1).max(160),
10
11
  bindings: v3_1.z.array(analytics_1.analyticsBindingSchema).max(8),
12
+ sourceMetadata: dashboard_sources_1.sourceMetadataSchema.optional(),
13
+ components: dashboard_sources_1.dashboardComponentsSchema.optional(),
11
14
  presentation: v3_1.z.object({ type: v3_1.z.literal('html'), html: artifact_document_1.artifactDocumentHtml, dependencies: artifact_document_1.artifactDocumentDependencyLocks.optional() }).strict().optional(),
12
15
  controls: v3_1.z.array(v3_1.z.object({ controlId: id, type: v3_1.z.enum(['string', 'number', 'boolean', 'date']),
13
16
  defaultValue: v3_1.z.union([v3_1.z.string(), v3_1.z.number(), v3_1.z.boolean(), v3_1.z.null()]).optional(),
@@ -25,6 +28,20 @@ exports.dashboardSchema = v3_1.z.object({
25
28
  ctx.addIssue({ code: 'custom', message: 'An unconfigured draft must contain no views or controls' });
26
29
  unique(manifest.bindings.map((binding) => binding.id), 'binding');
27
30
  unique(manifest.bindings.map((binding) => binding.output.datasetId), 'dataset');
31
+ unique((manifest.sourceMetadata ?? []).map(item => item.bindingId), 'source metadata');
32
+ unique((manifest.components ?? []).map(item => item.id), 'component');
33
+ unique((manifest.components ?? []).map(item => item.elementId), 'component element');
34
+ for (const metadata of manifest.sourceMetadata ?? [])
35
+ if (!manifest.bindings.some(binding => binding.id === metadata.bindingId))
36
+ ctx.addIssue({ code: 'custom', message: 'Source metadata references an undeclared Binding' });
37
+ for (const component of manifest.components ?? []) {
38
+ unique(component.sources.map(source => source.bindingId), 'component source');
39
+ for (const source of component.sources) {
40
+ const binding = manifest.bindings.find(item => item.id === source.bindingId);
41
+ if (!binding || source.fieldIds?.some(field => !binding.output.fields.some(item => item.id === field)))
42
+ ctx.addIssue({ code: 'custom', message: 'Component references an undeclared Binding or field' });
43
+ }
44
+ }
28
45
  unique(manifest.controls.map((control) => control.controlId), 'control');
29
46
  unique([...manifest.charts, ...manifest.tables].map((view) => view.id), 'view');
30
47
  if (manifest.bindings.length && !manifest.presentation && !manifest.charts.length && !manifest.tables.length)
@@ -68,7 +85,7 @@ exports.dashboardSchema = v3_1.z.object({
68
85
  });
69
86
  /** Updates never choose identity or source scope; those come from the authorized saved version. */
70
87
  exports.dashboardChangesSchema = exports.dashboardSchema.innerType().pick({ title: true, bindings: true,
71
- controls: true, charts: true, tables: true, presentation: true }).partial().strict();
88
+ controls: true, charts: true, tables: true, presentation: true, sourceMetadata: true, components: true }).partial().strict();
72
89
  exports.controlsSchema = v3_1.z.record(v3_1.z.union([v3_1.z.string().max(4000), v3_1.z.number().finite(), v3_1.z.boolean(), v3_1.z.null()]));
73
90
  exports.saveSchema = v3_1.z.object({ manifest: exports.dashboardSchema, expectedVersionId: v3_1.z.string().uuid().nullable(), expectedRevision: v3_1.z.number().int().nonnegative().default(0) }).strict();
74
91
  exports.querySchema = v3_1.z.object({ artifactId: v3_1.z.string().uuid(), versionId: v3_1.z.string().uuid().optional(), draftRevision: v3_1.z.number().int().positive().optional(), controls: exports.controlsSchema.default({}) }).strict();
@@ -1,6 +1,7 @@
1
1
  import type { AnalyticsValue, AnalyticsDiscoveryRequest, AnalyticsQueryRequest, XpertResolvedViewHostContext } from '@xpert-ai/contracts';
2
2
  import { type RuntimeCapabilityRegistry } from '@xpert-ai/plugin-sdk';
3
3
  import { type DashboardManifest, type DashboardChanges } from './dashboard.schema';
4
+ import { type ArtifactDocumentDependencyAsset } from '@xpert-ai/plugin-sdk/artifact-document';
4
5
  import { HtmlDashboardValidation } from './html-validation';
5
6
  import type { DashboardAccess, DashboardMode } from './project';
6
7
  export declare const PLUGIN_NAME = "@xpert-ai/plugin-live-dashboard";
@@ -14,11 +15,11 @@ export declare class DashboardService {
14
15
  list(context: XpertResolvedViewHostContext): Promise<{
15
16
  title: string | null | undefined;
16
17
  draftRevision?: number | undefined;
18
+ updatedAt: string | Date | undefined;
17
19
  canDelete: boolean;
18
20
  artifactId: string;
19
21
  versionId: string | null | undefined;
20
22
  versionNumber: number | undefined;
21
- updatedAt: string | Date | undefined;
22
23
  }[]>;
23
24
  access(context: XpertResolvedViewHostContext): Promise<DashboardAccess>;
24
25
  listPage(context: XpertResolvedViewHostContext, page?: number, pageSize?: number): Promise<{
@@ -28,11 +29,11 @@ export declare class DashboardService {
28
29
  items: {
29
30
  title: string | null | undefined;
30
31
  draftRevision?: number | undefined;
32
+ updatedAt: string | Date | undefined;
31
33
  canDelete: boolean;
32
34
  artifactId: string;
33
35
  versionId: string | null | undefined;
34
36
  versionNumber: number | undefined;
35
- updatedAt: string | Date | undefined;
36
37
  }[];
37
38
  }>;
38
39
  searchPage(context: XpertResolvedViewHostContext, input: {
@@ -42,19 +43,28 @@ export declare class DashboardService {
42
43
  items: {
43
44
  title: string | null | undefined;
44
45
  draftRevision?: number | undefined;
46
+ updatedAt: string | Date | undefined;
45
47
  canDelete: boolean;
46
48
  artifactId: string;
47
49
  versionId: string | null | undefined;
48
50
  versionNumber: number | undefined;
49
- updatedAt: string | Date | undefined;
50
51
  }[];
51
52
  page: number;
52
53
  hasMore: boolean;
53
54
  }>;
55
+ selectedSummary(context: XpertResolvedViewHostContext, artifactId: string): Promise<{
56
+ title: string | null | undefined;
57
+ draftRevision?: number | undefined;
58
+ canDelete: boolean;
59
+ artifactId: string;
60
+ versionId: string | null | undefined;
61
+ versionNumber: number | undefined;
62
+ updatedAt: string | Date | undefined;
63
+ } | undefined>;
54
64
  trash(context: XpertResolvedViewHostContext, artifactId: string, expectedRevision: number): Promise<{
55
65
  artifactId: string;
56
66
  }>;
57
- save(context: XpertResolvedViewHostContext, manifest: DashboardManifest, expectedVersionId: string | null, expectedRevision?: number): Promise<{
67
+ save(context: XpertResolvedViewHostContext, manifest: DashboardManifest, expectedVersionId: string | null, expectedRevision?: number, importedDependencies?: ArtifactDocumentDependencyAsset[]): Promise<{
58
68
  artifactId: string;
59
69
  draftId: string;
60
70
  draftRevision: number;
@@ -64,9 +74,9 @@ export declare class DashboardService {
64
74
  }>;
65
75
  open(context: XpertResolvedViewHostContext, artifactId: string, versionId?: string, draftRevision?: number, mode?: DashboardMode): Promise<{
66
76
  manifest: {
67
- schema: "xpert.live-dashboard";
68
- id: string;
69
77
  title: string;
78
+ id: string;
79
+ schema: "xpert.live-dashboard";
70
80
  bindings: import("@xpert-ai/contracts").AnalyticsBinding[];
71
81
  controls: {
72
82
  type: "string" | "number" | "boolean" | "date";
@@ -76,20 +86,35 @@ export declare class DashboardService {
76
86
  allowedValues?: (string | number | boolean | null)[] | undefined;
77
87
  }[];
78
88
  charts: {
89
+ title: string;
79
90
  type: "bar" | "line" | "area" | "pie" | "scatter";
80
91
  id: string;
81
- title: string;
82
92
  datasetId: string;
83
93
  x: string;
84
94
  y: string;
85
95
  color?: string | undefined;
86
96
  }[];
87
97
  tables: {
88
- id: string;
89
98
  title: string;
99
+ id: string;
90
100
  datasetId: string;
91
101
  fields: string[];
92
102
  }[];
103
+ sourceMetadata?: {
104
+ bindingId: string;
105
+ title: string;
106
+ description?: string | undefined;
107
+ }[] | undefined;
108
+ components?: {
109
+ title: string;
110
+ id: string;
111
+ elementId: string;
112
+ kind: "filter" | "metric" | "chart" | "table" | "text";
113
+ sources: {
114
+ bindingId: string;
115
+ fieldIds?: string[] | undefined;
116
+ }[];
117
+ }[] | undefined;
93
118
  presentation?: {
94
119
  type: "html";
95
120
  html: string;
@@ -110,9 +135,9 @@ export declare class DashboardService {
110
135
  /** Trusted View transport only. Agent read tools receive locks, never megabytes of library code. */
111
136
  openDocument(context: XpertResolvedViewHostContext, artifactId: string, versionId?: string, draftRevision?: number, mode?: DashboardMode): Promise<{
112
137
  manifest: {
113
- schema: "xpert.live-dashboard";
114
- id: string;
115
138
  title: string;
139
+ id: string;
140
+ schema: "xpert.live-dashboard";
116
141
  bindings: import("@xpert-ai/contracts").AnalyticsBinding[];
117
142
  controls: {
118
143
  type: "string" | "number" | "boolean" | "date";
@@ -122,27 +147,42 @@ export declare class DashboardService {
122
147
  allowedValues?: (string | number | boolean | null)[] | undefined;
123
148
  }[];
124
149
  charts: {
150
+ title: string;
125
151
  type: "bar" | "line" | "area" | "pie" | "scatter";
126
152
  id: string;
127
- title: string;
128
153
  datasetId: string;
129
154
  x: string;
130
155
  y: string;
131
156
  color?: string | undefined;
132
157
  }[];
133
158
  tables: {
134
- id: string;
135
159
  title: string;
160
+ id: string;
136
161
  datasetId: string;
137
162
  fields: string[];
138
163
  }[];
164
+ sourceMetadata?: {
165
+ bindingId: string;
166
+ title: string;
167
+ description?: string | undefined;
168
+ }[] | undefined;
169
+ components?: {
170
+ title: string;
171
+ id: string;
172
+ elementId: string;
173
+ kind: "filter" | "metric" | "chart" | "table" | "text";
174
+ sources: {
175
+ bindingId: string;
176
+ fieldIds?: string[] | undefined;
177
+ }[];
178
+ }[] | undefined;
139
179
  presentation?: {
140
180
  type: "html";
141
181
  html: string;
142
182
  dependencies?: import("@xpert-ai/plugin-sdk/artifact-document").ArtifactDocumentDependencyLock[] | undefined;
143
183
  } | undefined;
144
184
  };
145
- dependencies: import("@xpert-ai/plugin-sdk/artifact-document").ArtifactDocumentDependencyAsset[];
185
+ dependencies: ArtifactDocumentDependencyAsset[];
146
186
  contentHash: string;
147
187
  draftId?: string | undefined;
148
188
  draftRevision?: number | undefined;
@@ -241,9 +281,9 @@ export declare class DashboardService {
241
281
  reason: "unavailable";
242
282
  }[];
243
283
  manifest: {
244
- schema: "xpert.live-dashboard";
245
- id: string;
246
284
  title: string;
285
+ id: string;
286
+ schema: "xpert.live-dashboard";
247
287
  bindings: import("@xpert-ai/contracts").AnalyticsBinding[];
248
288
  controls: {
249
289
  type: "string" | "number" | "boolean" | "date";
@@ -253,20 +293,35 @@ export declare class DashboardService {
253
293
  allowedValues?: (string | number | boolean | null)[] | undefined;
254
294
  }[];
255
295
  charts: {
296
+ title: string;
256
297
  type: "bar" | "line" | "area" | "pie" | "scatter";
257
298
  id: string;
258
- title: string;
259
299
  datasetId: string;
260
300
  x: string;
261
301
  y: string;
262
302
  color?: string | undefined;
263
303
  }[];
264
304
  tables: {
265
- id: string;
266
305
  title: string;
306
+ id: string;
267
307
  datasetId: string;
268
308
  fields: string[];
269
309
  }[];
310
+ sourceMetadata?: {
311
+ bindingId: string;
312
+ title: string;
313
+ description?: string | undefined;
314
+ }[] | undefined;
315
+ components?: {
316
+ title: string;
317
+ id: string;
318
+ elementId: string;
319
+ kind: "filter" | "metric" | "chart" | "table" | "text";
320
+ sources: {
321
+ bindingId: string;
322
+ fieldIds?: string[] | undefined;
323
+ }[];
324
+ }[] | undefined;
270
325
  presentation?: {
271
326
  type: "html";
272
327
  html: string;
@@ -18,6 +18,8 @@ const common_1 = require("@nestjs/common");
18
18
  const node_crypto_1 = require("node:crypto");
19
19
  const plugin_sdk_1 = require("@xpert-ai/plugin-sdk");
20
20
  const dashboard_schema_1 = require("./dashboard.schema");
21
+ const source_validation_1 = require("./source-validation");
22
+ const artifact_document_1 = require("@xpert-ai/plugin-sdk/artifact-document");
21
23
  const renderer_1 = require("./renderer");
22
24
  const dashboard_queries_1 = require("./dashboard-queries");
23
25
  const html_validation_1 = require("./html-validation");
@@ -59,7 +61,7 @@ let DashboardService = class DashboardService {
59
61
  return { page, pageSize, hasMore: page * pageSize < result.total, items: items.filter(item => access.canReadDraft || !!item.currentVersionId).map(item => {
60
62
  const draft = drafts.get(item.id);
61
63
  return { ...summary(item), canDelete: !!draft && access.canManage,
62
- ...(draft ? { title: draft.title ?? item.title, draftRevision: draft.revision } : {}) };
64
+ ...(draft ? { title: draft.title ?? item.title, draftRevision: draft.revision, updatedAt: draft.updatedAt ?? item.updatedAt } : {}) };
63
65
  }) };
64
66
  }
65
67
  async searchPage(context, input) {
@@ -76,6 +78,18 @@ let DashboardService = class DashboardService {
76
78
  }
77
79
  return { items: matches.slice(offset, offset + pageSize), page: input.page, hasMore: matches.length > offset + pageSize };
78
80
  }
81
+ async selectedSummary(context, artifactId) {
82
+ const access = await this.access(context);
83
+ const artifact = await this.runtime.require(plugin_sdk_1.ArtifactsRuntimeCapability).getArtifact(artifactId);
84
+ assertOwned(context, artifact);
85
+ if (artifact.status !== 'active')
86
+ throw new common_1.ForbiddenException('DASHBOARD_ARCHIVED');
87
+ if (!access.canReadDraft && !artifact.currentVersionId)
88
+ return undefined;
89
+ const draft = access.canReadDraft ? (await this.runtime.require(plugin_sdk_1.ArtifactDraftsRuntimeCapability).list([artifactId]))[0] : undefined;
90
+ return { ...summary(artifact), canDelete: !!draft && access.canManage,
91
+ ...(draft ? { title: draft.title ?? artifact.title, draftRevision: draft.revision } : {}) };
92
+ }
79
93
  async trash(context, artifactId, expectedRevision) {
80
94
  await this.authorizeProject(context, 'manage');
81
95
  const artifact = await this.runtime.require(plugin_sdk_1.ArtifactsRuntimeCapability).getArtifact(artifactId);
@@ -86,10 +100,11 @@ let DashboardService = class DashboardService {
86
100
  await this.runtime.require(plugin_sdk_1.ArtifactDraftsRuntimeCapability).setRecycled({ artifactId, expectedRevision, recycled: true });
87
101
  return { artifactId };
88
102
  }
89
- async save(context, manifest, expectedVersionId, expectedRevision = 0) {
103
+ async save(context, manifest, expectedVersionId, expectedRevision = 0, importedDependencies) {
90
104
  await this.authorizeProject(context, 'write');
91
105
  const scopedActor = actor(context);
92
106
  const parsed = dashboard_schema_1.dashboardSchema.parse(manifest);
107
+ (0, source_validation_1.assertComponentElements)(parsed);
93
108
  const artifacts = this.runtime.require(plugin_sdk_1.ArtifactsRuntimeCapability);
94
109
  const source = { pluginName: exports.PLUGIN_NAME, resourceType: RESOURCE_TYPE, resourceId: `${hostPrefix(context)}${parsed.id}` };
95
110
  const existing = await artifacts.findArtifactBySource(source);
@@ -100,7 +115,10 @@ let DashboardService = class DashboardService {
100
115
  }
101
116
  // A failed first upload can leave an Artifact with no saved content; revision 0 initializes it.
102
117
  const previous = existing && (existing.currentVersionId || expectedRevision > 0) ? await this.openDocument(context, existing.id) : null;
103
- const dependencies = await (0, document_libraries_1.resolveLibraryAssets)(parsed.presentation?.dependencies ?? [], previous?.dependencies);
118
+ if (importedDependencies && existing)
119
+ throw new common_1.BadRequestException('DASHBOARD_IMPORT_NEW_ID_REQUIRED');
120
+ const dependencies = importedDependencies ? (0, artifact_document_1.verifyArtifactDocumentDependencies)(importedDependencies, parsed.presentation?.dependencies ?? [])
121
+ : await (0, document_libraries_1.resolveLibraryAssets)(parsed.presentation?.dependencies ?? [], previous?.dependencies);
104
122
  const buffer = (0, document_package_1.encodeDashboardPackage)(parsed, dependencies);
105
123
  if (buffer.byteLength > document_package_1.MAX_DASHBOARD_PACKAGE_BYTES)
106
124
  throw new common_1.BadRequestException('DASHBOARD_MANIFEST_TOO_LARGE');
@@ -5,9 +5,9 @@ export declare const MAX_DASHBOARD_PACKAGE_BYTES = 9000000;
5
5
  export declare function encodeDashboardPackage(manifest: DashboardManifest, dependencies: ArtifactDocumentDependencyAsset[]): Buffer<ArrayBuffer>;
6
6
  export declare function decodeDashboardPackage(bytes: Buffer): {
7
7
  manifest: {
8
- schema: "xpert.live-dashboard";
9
- id: string;
10
8
  title: string;
9
+ id: string;
10
+ schema: "xpert.live-dashboard";
11
11
  bindings: import("@xpert-ai/contracts").AnalyticsBinding[];
12
12
  controls: {
13
13
  type: "string" | "number" | "boolean" | "date";
@@ -17,20 +17,35 @@ export declare function decodeDashboardPackage(bytes: Buffer): {
17
17
  allowedValues?: (string | number | boolean | null)[] | undefined;
18
18
  }[];
19
19
  charts: {
20
+ title: string;
20
21
  type: "bar" | "line" | "area" | "pie" | "scatter";
21
22
  id: string;
22
- title: string;
23
23
  datasetId: string;
24
24
  x: string;
25
25
  y: string;
26
26
  color?: string | undefined;
27
27
  }[];
28
28
  tables: {
29
- id: string;
30
29
  title: string;
30
+ id: string;
31
31
  datasetId: string;
32
32
  fields: string[];
33
33
  }[];
34
+ sourceMetadata?: {
35
+ bindingId: string;
36
+ title: string;
37
+ description?: string | undefined;
38
+ }[] | undefined;
39
+ components?: {
40
+ title: string;
41
+ id: string;
42
+ elementId: string;
43
+ kind: "filter" | "metric" | "chart" | "table" | "text";
44
+ sources: {
45
+ bindingId: string;
46
+ fieldIds?: string[] | undefined;
47
+ }[];
48
+ }[] | undefined;
34
49
  presentation?: {
35
50
  type: "html";
36
51
  html: string;
@@ -5,16 +5,19 @@ export declare const removalsSchema: z.ZodOptional<z.ZodObject<{
5
5
  controlIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
6
6
  viewIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
7
7
  htmlElementIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
8
+ componentIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
8
9
  }, "strict", z.ZodTypeAny, {
9
10
  bindingIds: string[];
10
11
  controlIds: string[];
11
12
  viewIds: string[];
12
13
  htmlElementIds: string[];
14
+ componentIds: string[];
13
15
  }, {
14
16
  bindingIds?: string[] | undefined;
15
17
  controlIds?: string[] | undefined;
16
18
  viewIds?: string[] | undefined;
17
19
  htmlElementIds?: string[] | undefined;
20
+ componentIds?: string[] | undefined;
18
21
  }>>;
19
22
  export declare function upsertComponents<T>(existing: T[], changes: T[] | undefined, id: (item: T) => string, removed?: string[]): T[];
20
23
  export declare function htmlElementIds(html: string): Set<string>;
@@ -8,7 +8,8 @@ const parse5_1 = require("parse5");
8
8
  const v3_1 = require("zod/v3");
9
9
  exports.removalsSchema = v3_1.z.object({
10
10
  bindingIds: v3_1.z.array(v3_1.z.string()).max(8).default([]), controlIds: v3_1.z.array(v3_1.z.string()).max(24).default([]),
11
- viewIds: v3_1.z.array(v3_1.z.string()).max(40).default([]), htmlElementIds: v3_1.z.array(v3_1.z.string()).max(500).default([])
11
+ viewIds: v3_1.z.array(v3_1.z.string()).max(40).default([]), htmlElementIds: v3_1.z.array(v3_1.z.string()).max(500).default([]),
12
+ componentIds: v3_1.z.array(v3_1.z.string()).max(160).default([])
12
13
  }).strict().optional().describe('Only explicitly requested removals. Arrays of changed components otherwise upsert by stable ID and preserve omitted components.');
13
14
  function upsertComponents(existing, changes, id, removed = []) {
14
15
  if (new Set(changes?.map(id)).size !== (changes?.length ?? 0))
@@ -84,41 +84,41 @@ export declare const dashboardStateSchema: z.ZodObject<{
84
84
  draftRevision?: number | undefined;
85
85
  }>>;
86
86
  }, "strip", z.ZodTypeAny, {
87
+ scope: string;
87
88
  target: {
88
89
  artifactId: string;
89
90
  schemaVersion: 1;
90
91
  versionId?: string | undefined;
91
92
  draftRevision?: number | undefined;
92
93
  } | null;
93
- scope: string;
94
94
  }, {
95
+ scope: string;
95
96
  target: {
96
97
  artifactId: string;
97
98
  schemaVersion: 1;
98
99
  versionId?: string | undefined;
99
100
  draftRevision?: number | undefined;
100
101
  } | null;
101
- scope: string;
102
102
  }>>>;
103
103
  }, "strip", z.ZodTypeAny, {
104
104
  dashboardEditing?: {
105
+ scope: string;
105
106
  target: {
106
107
  artifactId: string;
107
108
  schemaVersion: 1;
108
109
  versionId?: string | undefined;
109
110
  draftRevision?: number | undefined;
110
111
  } | null;
111
- scope: string;
112
112
  } | null | undefined;
113
113
  }, {
114
114
  dashboardEditing?: {
115
+ scope: string;
115
116
  target: {
116
117
  artifactId: string;
117
118
  schemaVersion: 1;
118
119
  versionId?: string | undefined;
119
120
  draftRevision?: number | undefined;
120
121
  } | null;
121
- scope: string;
122
122
  } | null | undefined;
123
123
  }>;
124
124
  /** Checkpoints belong to an actor and conversation. Copied state must never choose another user's target. */