@praxisui/page-builder 9.0.35 → 9.0.36

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.
@@ -7,7 +7,7 @@ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
7
7
  import * as i2$1 from '@angular/material/icon';
8
8
  import { MatIconModule } from '@angular/material/icon';
9
9
  import * as i2$2 from '@praxisui/core';
10
- import { PraxisIconDirective, providePraxisI18n, BUILTIN_SHELL_PRESETS, PraxisIconButtonComponent, PraxisI18nService, GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, PRAXIS_GLOBAL_ACTION_CATALOG, SurfaceOpenActionEditorComponent, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, NestedWidgetConfigAccessor, deepMerge, generateId, ComponentMetadataRegistry, ObservabilityDashboardService, PraxisRuntimeComponentObservationRegistryService, domainKnowledgeTimelineToRichContentDocument, DomainRuleService, DomainKnowledgeService, SETTINGS_PANEL_BRIDGE, DynamicWidgetPageComponent, DYNAMIC_PAGE_SHELL_EDITOR } from '@praxisui/core';
10
+ import { PraxisIconDirective, providePraxisI18n, BUILTIN_SHELL_PRESETS, PraxisIconButtonComponent, PraxisI18nService, GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, PRAXIS_GLOBAL_ACTION_CATALOG, SurfaceOpenActionEditorComponent, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, NestedWidgetConfigAccessor, CompositionValidatorService, deepMerge, generateId, ComponentMetadataRegistry, ObservabilityDashboardService, PraxisRuntimeComponentObservationRegistryService, domainKnowledgeTimelineToRichContentDocument, DomainRuleService, DomainKnowledgeService, SETTINGS_PANEL_BRIDGE, DynamicWidgetPageComponent, DYNAMIC_PAGE_SHELL_EDITOR } from '@praxisui/core';
11
11
  import * as i3 from '@angular/material/tooltip';
12
12
  import { MatTooltipModule } from '@angular/material/tooltip';
13
13
  import * as i3$1 from '@angular/material/form-field';
@@ -4043,10 +4043,10 @@ function buildConnectionsViewerModel(page) {
4043
4043
  const fromWidgetId = link.from.kind === 'component-port' ? link.from.ref.widget : null;
4044
4044
  const toWidgetId = link.to.kind === 'component-port' ? link.to.ref.widget : null;
4045
4045
  const fromNestedPath = link.from.kind === 'component-port' && link.from.ref.nestedPath?.length
4046
- ? clone$2(link.from.ref.nestedPath)
4046
+ ? clone$3(link.from.ref.nestedPath)
4047
4047
  : null;
4048
4048
  const toNestedPath = link.to.kind === 'component-port' && link.to.ref.nestedPath?.length
4049
- ? clone$2(link.to.ref.nestedPath)
4049
+ ? clone$3(link.to.ref.nestedPath)
4050
4050
  : null;
4051
4051
  const toStatePath = link.to.kind === 'state' ? link.to.ref.path : null;
4052
4052
  const diagnosticReasons = [];
@@ -4131,7 +4131,7 @@ function formatPathSegment$1(segment) {
4131
4131
  segment.id || segment.key || segment.index,
4132
4132
  ].filter((part) => part !== undefined && part !== '').join(':');
4133
4133
  }
4134
- function clone$2(value) {
4134
+ function clone$3(value) {
4135
4135
  if (value == null || typeof value !== 'object')
4136
4136
  return value;
4137
4137
  return JSON.parse(JSON.stringify(value));
@@ -4443,8 +4443,8 @@ function buildCompositionLinkFromPorts(source, target, links) {
4443
4443
  const transform = inferCanonicalTransform(source, target);
4444
4444
  return {
4445
4445
  id: uniqueConnectionLinkId(source, target, links),
4446
- from: clone$1(source.endpoint),
4447
- to: clone$1(target.endpoint),
4446
+ from: clone$2(source.endpoint),
4447
+ to: clone$2(target.endpoint),
4448
4448
  intent: inferConnectionIntent(source, target),
4449
4449
  ...(transform ? { transform } : {}),
4450
4450
  metadata: {
@@ -4585,7 +4585,7 @@ function componentPort(widgetId, port, direction, componentType, nestedPath, lab
4585
4585
  port,
4586
4586
  direction,
4587
4587
  ...(componentType ? { componentType } : {}),
4588
- ...(nestedPath?.length ? { nestedPath: clone$1(nestedPath) } : {}),
4588
+ ...(nestedPath?.length ? { nestedPath: clone$2(nestedPath) } : {}),
4589
4589
  },
4590
4590
  };
4591
4591
  return {
@@ -4599,7 +4599,7 @@ function componentPort(widgetId, port, direction, componentType, nestedPath, lab
4599
4599
  label,
4600
4600
  kind: direction,
4601
4601
  endpoint,
4602
- ...(nestedPath?.length ? { nestedPath: clone$1(nestedPath) } : {}),
4602
+ ...(nestedPath?.length ? { nestedPath: clone$2(nestedPath) } : {}),
4603
4603
  };
4604
4604
  }
4605
4605
  function statePort(path) {
@@ -4867,7 +4867,7 @@ function readArray(value) {
4867
4867
  function readString(value) {
4868
4868
  return typeof value === 'string' && value.trim() ? value : undefined;
4869
4869
  }
4870
- function clone$1(value) {
4870
+ function clone$2(value) {
4871
4871
  if (value == null || typeof value !== 'object')
4872
4872
  return value;
4873
4873
  return JSON.parse(JSON.stringify(value));
@@ -7343,7 +7343,7 @@ class ConnectionEditorComponent {
7343
7343
  ...(current ?? {}),
7344
7344
  debounceMs: 150,
7345
7345
  distinct: true,
7346
- delivery: 'microtask',
7346
+ delivery: 'sync',
7347
7347
  };
7348
7348
  }
7349
7349
  applyNodeRotation(node) {
@@ -11382,9 +11382,10 @@ class PageConfigEditorComponent {
11382
11382
  this.patchDeviceLayoutForm(this.deviceMobileForm, deviceLayouts?.mobile);
11383
11383
  }
11384
11384
  buildDeviceLayouts() {
11385
- const desktop = this.buildDeviceLayoutVariant(this.deviceDesktopForm);
11386
- const tablet = this.buildDeviceLayoutVariant(this.deviceTabletForm);
11387
- const mobile = this.buildDeviceLayoutVariant(this.deviceMobileForm);
11385
+ const current = this.currentPageInput()?.deviceLayouts;
11386
+ const desktop = this.buildDeviceLayoutVariant(this.deviceDesktopForm, current?.desktop);
11387
+ const tablet = this.buildDeviceLayoutVariant(this.deviceTabletForm, current?.tablet);
11388
+ const mobile = this.buildDeviceLayoutVariant(this.deviceMobileForm, current?.mobile);
11388
11389
  if (desktop === null || tablet === null || mobile === null)
11389
11390
  return null;
11390
11391
  const deviceLayouts = {};
@@ -11419,7 +11420,7 @@ class PageConfigEditorComponent {
11419
11420
  widgetOverridesJson: variant?.widgetOverrides ? JSON.stringify(variant.widgetOverrides, null, 2) : '',
11420
11421
  }, { emitEvent: false });
11421
11422
  }
11422
- buildDeviceLayoutVariant(form) {
11423
+ buildDeviceLayoutVariant(form, current) {
11423
11424
  const breakpoints = this.parseJson(form.controls.breakpointsJson.value, {});
11424
11425
  const groupingOverrides = this.parseJson(form.controls.groupingOverridesJson.value, []);
11425
11426
  const widgetOverrides = this.parseJson(form.controls.widgetOverridesJson.value, {});
@@ -11434,13 +11435,19 @@ class PageConfigEditorComponent {
11434
11435
  layout.gap = form.controls.gap.value.trim();
11435
11436
  if (Object.keys(breakpoints).length)
11436
11437
  layout.breakpoints = breakpoints;
11437
- const variant = {};
11438
+ const variant = this.clone(current || {});
11438
11439
  if (Object.keys(layout).length)
11439
11440
  variant.layout = layout;
11441
+ else
11442
+ delete variant.layout;
11440
11443
  if (groupingOverrides.length)
11441
11444
  variant.groupingOverrides = groupingOverrides;
11445
+ else
11446
+ delete variant.groupingOverrides;
11442
11447
  if (Object.keys(widgetOverrides).length)
11443
11448
  variant.widgetOverrides = widgetOverrides;
11449
+ else
11450
+ delete variant.widgetOverrides;
11444
11451
  return variant;
11445
11452
  }
11446
11453
  hydrateStateEditor(state) {
@@ -13077,6 +13084,7 @@ const PAGE_BUILDER_AI_CAPABILITIES = {
13077
13084
  { path: 'uiCompositionPlan.widgets', category: 'widgets', valueKind: 'array', description: 'Widgets planejados antes da compilacao para page.widgets.' },
13078
13085
  { path: 'uiCompositionPlan.widgets[].key', category: 'widgets', valueKind: 'string', description: 'ID estavel do widget planejado.', critical: true },
13079
13086
  { path: 'uiCompositionPlan.widgets[].componentId', category: 'widgets', valueKind: 'string', description: 'Componente registrado que sera compilado para definition.id.', critical: true },
13087
+ { path: 'uiCompositionPlan.widgets[].role', category: 'layout', valueKind: 'string', description: 'Papel semantico explicito usado na materializacao de layout; master-detail aceita master, detail, filters, actions, supporting e os slots detail-* do preset oficial.' },
13080
13088
  { path: 'uiCompositionPlan.widgets[].shell', category: 'widgets', valueKind: 'object', description: 'Moldura governada do widget, compilada para page.widgets[].shell sem enriquecimento do host.' },
13081
13089
  { path: 'uiCompositionPlan.widgets[].inputs', category: 'widgets', valueKind: 'object', description: 'Inputs canonicos do componente, compilados para definition.inputs.' },
13082
13090
  { path: 'uiCompositionPlan.widgets[].bindingOrder', category: 'widgets', valueKind: 'array', description: 'Ordem declarativa de binding, compilada para definition.bindingOrder.' },
@@ -14310,14 +14318,14 @@ const PRAXIS_PAGE_BUILDER_AUTHORING_MANIFEST = {
14310
14318
  target: { kind: 'agenticPreview', resolver: 'agentic-preview-result', ambiguityPolicy: 'fail', required: true },
14311
14319
  inputSchema: { type: 'object', required: ['previewId'], properties: { previewId: { type: 'string' }, compiledFormPatch: { type: 'object' } } },
14312
14320
  effects: [{ kind: 'compile-domain-patch', handler: 'page-builder-preview-apply', handlerContract: {
14313
- reads: ['PageBuilderAiAdapter.applyCompiledFormPatch', 'compiledFormPatch.patch.page', 'PraxisAssistantTurnViewState'],
14321
+ reads: ['UiCompositionPlan', 'PageBuilderAiAdapter.applyUiCompositionPlan', 'ComponentMetadataRegistry', 'CompositionValidatorService.validatePage', 'compiledFormPatch.patch.page', 'PraxisAssistantTurnViewState'],
14314
14322
  writes: ['DynamicPageBuilderComponent.page', 'pageChange'],
14315
14323
  identityKeys: ['previewId'],
14316
- failureModes: ['preview-result-invalid', 'patch-page-missing', 'runtime-page-invalid', 'patch-envelope-persistence-attempted'],
14317
- description: 'Applies only compiledFormPatch.patch.page to the local runtime page; the backend envelope remains diagnostic data.',
14324
+ failureModes: ['preview-result-invalid', 'target-registry-missing', 'component-not-registered', 'component-not-materializable', 'port-not-registered', 'port-contract-incompatible', 'patch-page-missing', 'runtime-page-invalid', 'patch-envelope-persistence-attempted'],
14325
+ description: 'Preflights UiCompositionPlan against the target runtime registry and canonical Core composition validator before applying the attested WidgetPageDefinition locally.',
14318
14326
  } }],
14319
- validators: ['preview-result-valid', 'compiled-page-patch-present', 'no-envelope-runtime-persistence', 'runtime-page-valid'],
14320
- affectedPaths: ['compiledFormPatch.patch.page', 'page'],
14327
+ validators: ['preview-result-valid', 'ui-composition-target-registry-available', 'ui-composition-components-materializable', 'composition-endpoints-resolve', 'compiled-page-patch-present', 'no-envelope-runtime-persistence', 'runtime-page-valid'],
14328
+ affectedPaths: ['uiCompositionPlan', 'compiledFormPatch.patch.page', 'page'],
14321
14329
  submissionImpact: 'visual-only',
14322
14330
  preconditions: ['agentic-preview-loaded'],
14323
14331
  },
@@ -14398,6 +14406,8 @@ const PRAXIS_PAGE_BUILDER_AUTHORING_MANIFEST = {
14398
14406
  { validatorId: 'state-json-valid', level: 'error', code: 'PAGE_BUILDER_STATE_JSON', description: 'State values must be JSON-serializable.' },
14399
14407
  { validatorId: 'composition-state-links-still-valid', level: 'error', code: 'PAGE_BUILDER_STATE_LINKS', description: 'State edits must not break composition links.' },
14400
14408
  { validatorId: 'preview-result-valid', level: 'error', code: 'PAGE_BUILDER_PREVIEW_VALID', description: 'Agentic preview result must be structurally valid.' },
14409
+ { validatorId: 'ui-composition-target-registry-available', level: 'error', code: 'PAGE_BUILDER_UI_PLAN_TARGET_REGISTRY', description: 'UiCompositionPlan apply requires the ComponentMetadataRegistry of the target host.' },
14410
+ { validatorId: 'ui-composition-components-materializable', level: 'error', code: 'PAGE_BUILDER_UI_PLAN_COMPONENTS_MATERIALIZABLE', description: 'Every planned component must resolve materializable metadata in the target registry.' },
14401
14411
  { validatorId: 'compiled-page-patch-present', level: 'error', code: 'PAGE_BUILDER_PATCH_PAGE_PRESENT', description: 'Preview envelope must include compiledFormPatch.patch.page.' },
14402
14412
  { validatorId: 'no-envelope-runtime-persistence', level: 'error', code: 'PAGE_BUILDER_NO_ENVELOPE_PERSISTENCE', description: 'Runtime persistence cannot save the full preview envelope.' },
14403
14413
  { validatorId: 'runtime-page-valid', level: 'error', code: 'PAGE_BUILDER_RUNTIME_PAGE_VALID', description: 'Runtime page must remain renderable by praxis-dynamic-page.' },
@@ -14418,7 +14428,7 @@ const PRAXIS_PAGE_BUILDER_AUTHORING_MANIFEST = {
14418
14428
  'Persisted wiring uses page.composition.links and must not write legacy connections.',
14419
14429
  'Nested component ports use component-port refs with nestedPath ending in a stable widget key.',
14420
14430
  'Child widget definition.inputs edits delegate to the child manifest or ComponentDocMeta.configEditor.',
14421
- 'Agentic preview applies only compiledFormPatch.patch.page to runtime; the full patch envelope is diagnostics/audit data.',
14431
+ 'Agentic preview preflights UiCompositionPlan against the target registry and applies the attested WidgetPageDefinition; persistence rebuilds patch.page from that page while the surrounding envelope remains diagnostics/audit data.',
14422
14432
  'Save uses pageIdentity and ETag policy from praxis-config-starter; pageIdentity is not persisted inside WidgetPageDefinition.',
14423
14433
  'Settings panel apply/save/reset/reopen must preserve page settings and widget shell config without hidden normalization drift.',
14424
14434
  ],
@@ -14545,6 +14555,358 @@ const PRAXIS_PAGE_BUILDER_AUTHORING_MANIFEST = {
14545
14555
  ],
14546
14556
  };
14547
14557
 
14558
+ const MASTER_DETAIL_PRESET_ID = 'master-detail-dashboard';
14559
+ const MASTER_DETAIL_DETAIL_SLOTS = [
14560
+ 'detail-table',
14561
+ 'detail-chart-a',
14562
+ 'detail-chart-b',
14563
+ 'detail-kpis',
14564
+ ];
14565
+ const MASTER_DETAIL_SLOT_REGIONS = {
14566
+ master: 'master',
14567
+ 'detail-table': 'detail',
14568
+ 'detail-chart-a': 'detail',
14569
+ 'detail-chart-b': 'detail',
14570
+ 'detail-kpis': 'detail',
14571
+ };
14572
+ const MASTER_DETAIL_ROLE_REGIONS = {
14573
+ master: 'master',
14574
+ detail: 'detail',
14575
+ filters: 'filters',
14576
+ actions: 'actions',
14577
+ supporting: 'supporting',
14578
+ };
14579
+ function materializeUiCompositionPlanLayout(plan) {
14580
+ if (!isMasterDetailPlan(plan)) {
14581
+ return {
14582
+ layoutPresetOptions: clone$1(plan.layoutPresetOptions),
14583
+ canvas: resolveNeutralCanvas(plan),
14584
+ deviceLayouts: clone$1(plan.deviceLayouts),
14585
+ slotAssignments: clone$1(plan.slotAssignments),
14586
+ diagnostics: [],
14587
+ };
14588
+ }
14589
+ const analysis = analyzeMasterDetailPlan(plan);
14590
+ const canvas = plan.canvas
14591
+ ? clone$1(plan.canvas)
14592
+ : masterDetailCanvas(analysis.widgets, 12, 'desktop');
14593
+ const deviceLayouts = plan.deviceLayouts
14594
+ ? clone$1(plan.deviceLayouts)
14595
+ : materializeMasterDetailDeviceLayouts(analysis.widgets, canvas);
14596
+ return {
14597
+ layoutPresetOptions: materializeMasterDetailPresetOptions(plan),
14598
+ canvas,
14599
+ deviceLayouts,
14600
+ slotAssignments: Object.keys(analysis.slotAssignments).length
14601
+ ? analysis.slotAssignments
14602
+ : undefined,
14603
+ diagnostics: analysis.diagnostics,
14604
+ };
14605
+ }
14606
+ function validateUiCompositionPlanLayout(plan) {
14607
+ return isMasterDetailPlan(plan) ? analyzeMasterDetailPlan(plan).errors : [];
14608
+ }
14609
+ function isMasterDetailPlan(plan) {
14610
+ const preset = resolvePlanLayoutPreset(plan);
14611
+ const assignedRegions = Object.values(plan.slotAssignments ?? {})
14612
+ .map((slot) => MASTER_DETAIL_SLOT_REGIONS[String(slot || '').trim()])
14613
+ .filter((region) => !!region);
14614
+ const explicitRoles = (plan.widgets ?? [])
14615
+ .map((widget) => roleRegion(widget.role))
14616
+ .filter((region) => !!region);
14617
+ const regions = [...assignedRegions, ...explicitRoles];
14618
+ return (preset?.category === 'master-detail' ||
14619
+ (regions.includes('master') && regions.includes('detail')));
14620
+ }
14621
+ function roleRegion(role) {
14622
+ const semanticRole = String(role || '').trim();
14623
+ return (MASTER_DETAIL_ROLE_REGIONS[semanticRole] ??
14624
+ MASTER_DETAIL_SLOT_REGIONS[semanticRole]);
14625
+ }
14626
+ function resolvePlanLayoutPreset(plan) {
14627
+ const layoutPreset = String(plan.layoutPreset || '').trim();
14628
+ if (layoutPreset && BUILTIN_PAGE_LAYOUT_PRESETS[layoutPreset]) {
14629
+ return BUILTIN_PAGE_LAYOUT_PRESETS[layoutPreset];
14630
+ }
14631
+ const presetFamily = typeof plan.layoutPresetOptions?.['presetFamily'] === 'string'
14632
+ ? plan.layoutPresetOptions['presetFamily'].trim()
14633
+ : '';
14634
+ return presetFamily ? BUILTIN_PAGE_LAYOUT_PRESETS[presetFamily] : undefined;
14635
+ }
14636
+ function materializeMasterDetailPresetOptions(plan) {
14637
+ const options = clone$1(plan.layoutPresetOptions) ?? {};
14638
+ if (!resolvePlanLayoutPreset(plan) &&
14639
+ typeof options['presetFamily'] !== 'string') {
14640
+ options['presetFamily'] = MASTER_DETAIL_PRESET_ID;
14641
+ }
14642
+ return Object.keys(options).length ? options : undefined;
14643
+ }
14644
+ function analyzeMasterDetailPlan(plan) {
14645
+ const diagnostics = [];
14646
+ const errors = [];
14647
+ const explicitAssignments = clone$1(plan.slotAssignments) ?? {};
14648
+ const slotAssignments = { ...explicitAssignments };
14649
+ const resolvedPreset = resolvePlanLayoutPreset(plan);
14650
+ const layoutPreset = String(plan.layoutPreset || '').trim();
14651
+ const presetFamily = typeof plan.layoutPresetOptions?.['presetFamily'] === 'string'
14652
+ ? plan.layoutPresetOptions['presetFamily'].trim()
14653
+ : '';
14654
+ if (!BUILTIN_PAGE_LAYOUT_PRESETS[layoutPreset] &&
14655
+ presetFamily &&
14656
+ !BUILTIN_PAGE_LAYOUT_PRESETS[presetFamily]) {
14657
+ errors.push({
14658
+ code: 'master-detail-preset-family-unknown',
14659
+ message: `Preset family "${presetFamily}" is not declared by the layout preset catalog.`,
14660
+ path: 'layoutPresetOptions.presetFamily',
14661
+ });
14662
+ }
14663
+ const preset = resolvedPreset ?? BUILTIN_PAGE_LAYOUT_PRESETS[MASTER_DETAIL_PRESET_ID];
14664
+ const knownSlots = new Set(preset?.slotModel.map((slot) => slot.id) ?? []);
14665
+ const occupiedSlots = new Map();
14666
+ const widgets = [];
14667
+ for (const [index, widget] of (plan.widgets ?? []).entries()) {
14668
+ const explicitSlot = String(explicitAssignments[widget.key] || '').trim();
14669
+ const semanticRoleRegion = roleRegion(widget.role);
14670
+ const slotRegion = MASTER_DETAIL_SLOT_REGIONS[explicitSlot];
14671
+ if (explicitSlot && knownSlots.size && !knownSlots.has(explicitSlot)) {
14672
+ errors.push({
14673
+ code: 'master-detail-slot-unknown',
14674
+ message: `Slot "${explicitSlot}" is not declared by the resolved master-detail preset.`,
14675
+ path: `slotAssignments.${widget.key}`,
14676
+ });
14677
+ }
14678
+ if (semanticRoleRegion && slotRegion && semanticRoleRegion !== slotRegion) {
14679
+ errors.push({
14680
+ code: 'master-detail-role-slot-conflict',
14681
+ message: `Widget "${widget.key}" has conflicting semantic role and slot assignment.`,
14682
+ path: `slotAssignments.${widget.key}`,
14683
+ });
14684
+ }
14685
+ const region = slotRegion ?? semanticRoleRegion ?? 'supporting';
14686
+ if (!slotRegion && !semanticRoleRegion) {
14687
+ diagnostics.push({
14688
+ code: 'master-detail-widget-role-fallback',
14689
+ message: `Widget "${widget.key}" has no recognized semantic role or preset slot and was placed in supporting content.`,
14690
+ path: `widgets.${index}.role`,
14691
+ });
14692
+ }
14693
+ widgets.push({ widget, index, region, slot: explicitSlot || undefined });
14694
+ }
14695
+ if (resolvedPreset && resolvedPreset.category !== 'master-detail') {
14696
+ errors.push({
14697
+ code: 'master-detail-preset-conflict',
14698
+ message: 'Master and detail semantic roles require a master-detail layout preset family.',
14699
+ path: typeof plan.layoutPresetOptions?.['presetFamily'] === 'string'
14700
+ ? 'layoutPresetOptions.presetFamily'
14701
+ : 'layoutPreset',
14702
+ });
14703
+ }
14704
+ const masters = widgets.filter((item) => item.region === 'master');
14705
+ const details = widgets.filter((item) => item.region === 'detail');
14706
+ if (!masters.length) {
14707
+ errors.push({
14708
+ code: 'master-detail-master-required',
14709
+ message: 'A master-detail plan must declare exactly one master widget through role or slot assignment.',
14710
+ path: 'widgets',
14711
+ });
14712
+ }
14713
+ else if (masters.length > 1) {
14714
+ errors.push({
14715
+ code: 'master-detail-master-ambiguous',
14716
+ message: 'A master-detail plan cannot declare more than one master widget.',
14717
+ path: 'widgets',
14718
+ });
14719
+ }
14720
+ if (!details.length) {
14721
+ errors.push({
14722
+ code: 'master-detail-detail-required',
14723
+ message: 'A master-detail plan must declare at least one detail widget through role or slot assignment.',
14724
+ path: 'widgets',
14725
+ });
14726
+ }
14727
+ for (const item of widgets) {
14728
+ if (!item.slot)
14729
+ continue;
14730
+ const occupants = occupiedSlots.get(item.slot) ?? [];
14731
+ occupiedSlots.set(item.slot, [...occupants, item.widget.key]);
14732
+ }
14733
+ for (const slot of preset?.slotModel ?? []) {
14734
+ const occupants = occupiedSlots.get(slot.id) ?? [];
14735
+ if (slot.maxItems != null && occupants.length > slot.maxItems) {
14736
+ errors.push({
14737
+ code: 'master-detail-slot-cardinality-exceeded',
14738
+ message: `Slot "${slot.id}" accepts at most ${slot.maxItems} widget(s).`,
14739
+ path: 'slotAssignments',
14740
+ });
14741
+ }
14742
+ }
14743
+ const availableDetailSlots = MASTER_DETAIL_DETAIL_SLOTS.filter((slot) => knownSlots.has(slot) && !occupiedSlots.has(slot));
14744
+ for (const item of widgets) {
14745
+ if (item.slot || item.region !== 'detail')
14746
+ continue;
14747
+ const preferredRoleSlot = exactDetailSlot(item.widget.role, knownSlots);
14748
+ const slot = preferredRoleSlot && !occupiedSlots.has(preferredRoleSlot)
14749
+ ? preferredRoleSlot
14750
+ : availableDetailSlots.find((candidate) => !occupiedSlots.has(candidate));
14751
+ if (!slot) {
14752
+ diagnostics.push({
14753
+ code: 'master-detail-detail-slot-fallback',
14754
+ message: `Widget "${item.widget.key}" exceeded the available detail slots and remains deterministic supporting content for grouping.`,
14755
+ path: `widgets.${item.index}.role`,
14756
+ });
14757
+ continue;
14758
+ }
14759
+ slotAssignments[item.widget.key] = slot;
14760
+ item.slot = slot;
14761
+ occupiedSlots.set(slot, [item.widget.key]);
14762
+ }
14763
+ const master = masters[0];
14764
+ if (master && !master.slot && knownSlots.has('master')) {
14765
+ slotAssignments[master.widget.key] = 'master';
14766
+ master.slot = 'master';
14767
+ }
14768
+ return { widgets, slotAssignments, diagnostics, errors };
14769
+ }
14770
+ function exactDetailSlot(role, knownSlots) {
14771
+ const candidate = String(role || '').trim();
14772
+ return MASTER_DETAIL_SLOT_REGIONS[candidate] === 'detail' &&
14773
+ knownSlots.has(candidate)
14774
+ ? candidate
14775
+ : undefined;
14776
+ }
14777
+ function resolveNeutralCanvas(plan) {
14778
+ if (plan.canvas)
14779
+ return clone$1(plan.canvas);
14780
+ if (!plan.widgets?.length)
14781
+ return undefined;
14782
+ if (plan.layout && !plan.layoutPreset?.trim())
14783
+ return undefined;
14784
+ const items = {};
14785
+ let row = 1;
14786
+ for (const widget of plan.widgets ?? []) {
14787
+ items[widget.key] = { col: 1, row, colSpan: 12, rowSpan: 4 };
14788
+ row += 4;
14789
+ }
14790
+ return defaultCanvas(items, 12, 'desktop');
14791
+ }
14792
+ function masterDetailCanvas(semantics, columns, device) {
14793
+ const items = {};
14794
+ const filters = semantics.filter((item) => item.region === 'filters');
14795
+ const actions = semantics.filter((item) => item.region === 'actions');
14796
+ const masters = semantics.filter((item) => item.region === 'master');
14797
+ const details = semantics.filter((item) => item.region === 'detail');
14798
+ const supporting = semantics.filter((item) => item.region === 'supporting');
14799
+ let row = 1;
14800
+ if (device === 'desktop' && filters.length && actions.length) {
14801
+ const filterEnd = placeHorizontal(items, filters, row, 1, 8, 'filters');
14802
+ const actionEnd = placeHorizontal(items, actions, row, 9, 4, 'actions');
14803
+ row = Math.max(filterEnd, actionEnd);
14804
+ }
14805
+ else {
14806
+ row = placeStacked(items, filters, row, columns, device);
14807
+ row = placeStacked(items, actions, row, columns, device);
14808
+ }
14809
+ if (device === 'desktop') {
14810
+ const contentRow = row;
14811
+ let detailRow = contentRow;
14812
+ for (const item of details) {
14813
+ const rowSpan = preferredRowSpan(item, device);
14814
+ items[item.widget.key] = { col: 5, row: detailRow, colSpan: 8, rowSpan };
14815
+ detailRow += rowSpan;
14816
+ }
14817
+ const contentHeight = Math.max(8, detailRow - contentRow);
14818
+ for (const item of masters) {
14819
+ items[item.widget.key] = {
14820
+ col: 1,
14821
+ row: contentRow,
14822
+ colSpan: 4,
14823
+ rowSpan: contentHeight,
14824
+ };
14825
+ }
14826
+ row = contentRow + contentHeight;
14827
+ }
14828
+ else {
14829
+ row = placeStacked(items, masters, row, columns, device);
14830
+ row = placeStacked(items, details, row, columns, device);
14831
+ }
14832
+ placeStacked(items, supporting, row, columns, device);
14833
+ return defaultCanvas(items, columns, device);
14834
+ }
14835
+ function placeHorizontal(items, semantics, row, col, colSpan, region) {
14836
+ let nextRow = row;
14837
+ for (const item of semantics) {
14838
+ const rowSpan = preferredRowSpan({ ...item, region }, 'desktop');
14839
+ items[item.widget.key] = { col, row: nextRow, colSpan, rowSpan };
14840
+ nextRow += rowSpan;
14841
+ }
14842
+ return nextRow;
14843
+ }
14844
+ function placeStacked(items, semantics, row, columns, device) {
14845
+ let nextRow = row;
14846
+ for (const item of semantics) {
14847
+ const rowSpan = preferredRowSpan(item, device);
14848
+ items[item.widget.key] = {
14849
+ col: 1,
14850
+ row: nextRow,
14851
+ colSpan: columns,
14852
+ rowSpan,
14853
+ };
14854
+ nextRow += rowSpan;
14855
+ }
14856
+ return nextRow;
14857
+ }
14858
+ function materializeMasterDetailDeviceLayouts(semantics, desktopCanvas) {
14859
+ const tablet = masterDetailCanvas(semantics, 6, 'tablet');
14860
+ const mobile = masterDetailCanvas(semantics, 1, 'mobile');
14861
+ return {
14862
+ desktop: { canvas: canvasVariant(desktopCanvas) },
14863
+ tablet: { canvas: canvasVariant(tablet) },
14864
+ mobile: { canvas: canvasVariant(mobile) },
14865
+ };
14866
+ }
14867
+ function canvasVariant(canvas) {
14868
+ return {
14869
+ columns: canvas.columns,
14870
+ rowUnit: canvas.rowUnit,
14871
+ gap: canvas.gap,
14872
+ autoRows: canvas.autoRows,
14873
+ ...(canvas.collisionPolicy
14874
+ ? { collisionPolicy: canvas.collisionPolicy }
14875
+ : {}),
14876
+ items: clone$1(canvas.items),
14877
+ };
14878
+ }
14879
+ function defaultCanvas(items, columns, device) {
14880
+ return {
14881
+ mode: 'grid',
14882
+ columns,
14883
+ rowUnit: device === 'desktop' ? '80px' : device === 'tablet' ? '72px' : '64px',
14884
+ gap: device === 'desktop' ? '16px' : '12px',
14885
+ autoRows: 'fixed',
14886
+ items,
14887
+ };
14888
+ }
14889
+ function preferredRowSpan(item, device) {
14890
+ if (item.region === 'filters' || item.region === 'actions')
14891
+ return 2;
14892
+ if (item.region === 'master')
14893
+ return device === 'desktop' ? 8 : 6;
14894
+ if (item.slot === 'detail-kpis')
14895
+ return 2;
14896
+ if (item.slot === 'detail-chart-a' || item.slot === 'detail-chart-b')
14897
+ return 5;
14898
+ if (item.slot === 'detail-table')
14899
+ return device === 'mobile' ? 6 : 7;
14900
+ if (item.region === 'detail')
14901
+ return device === 'mobile' ? 6 : 7;
14902
+ return 4;
14903
+ }
14904
+ function clone$1(value) {
14905
+ if (value === undefined || value === null)
14906
+ return value;
14907
+ return JSON.parse(JSON.stringify(value));
14908
+ }
14909
+
14548
14910
  /**
14549
14911
  * Pure, fail-closed normalization for an exact template reference.
14550
14912
  *
@@ -14606,16 +14968,17 @@ function compileUiCompositionPlan(plan) {
14606
14968
  }
14607
14969
  const bindings = expandedBindings(plan);
14608
14970
  const widgets = materializeContextScopeInputs(plan, plan.widgets.map((widget) => toWidgetInstance(widget, bindings)));
14971
+ const layoutMaterialization = materializeUiCompositionPlanLayout(plan);
14609
14972
  const page = {
14610
14973
  i18n: clone(plan.i18n),
14611
14974
  context: clone(plan.context),
14612
14975
  layout: clone(plan.layout),
14613
14976
  layoutPreset: plan.layoutPreset,
14614
- layoutPresetOptions: clone(plan.layoutPresetOptions),
14615
- canvas: resolveCanvas(plan),
14616
- deviceLayouts: clone(plan.deviceLayouts),
14977
+ layoutPresetOptions: layoutMaterialization.layoutPresetOptions,
14978
+ canvas: layoutMaterialization.canvas,
14979
+ deviceLayouts: layoutMaterialization.deviceLayouts,
14617
14980
  grouping: clone(plan.grouping),
14618
- slotAssignments: clone(plan.slotAssignments),
14981
+ slotAssignments: layoutMaterialization.slotAssignments,
14619
14982
  state: clone(plan.state),
14620
14983
  themePreset: plan.themePreset,
14621
14984
  widgets,
@@ -14627,7 +14990,7 @@ function compileUiCompositionPlan(plan) {
14627
14990
  return {
14628
14991
  valid: true,
14629
14992
  page: materializeLocalizedFallbacks(page),
14630
- diagnostics: [],
14993
+ diagnostics: layoutMaterialization.diagnostics,
14631
14994
  };
14632
14995
  }
14633
14996
  const SHA_256_PATTERN = /^[0-9a-f]{64}$/;
@@ -14714,95 +15077,6 @@ function materializeLocalizedFallbacks(page) {
14714
15077
  visit(materialized);
14715
15078
  return materialized;
14716
15079
  }
14717
- function resolveCanvas(plan) {
14718
- if (plan.canvas) {
14719
- return clone(plan.canvas);
14720
- }
14721
- if (!plan.widgets?.length) {
14722
- return undefined;
14723
- }
14724
- // An explicitly authored flow/grid layout is already a complete spatial
14725
- // decision. Synthesizing a canvas here would silently take precedence over
14726
- // that layout in the runtime. Preset- or role-driven plans still opt into
14727
- // automatic canvas materialization below.
14728
- if (plan.layout && !plan.layoutPreset?.trim() && !isMasterDetailPlan(plan)) {
14729
- return undefined;
14730
- }
14731
- if (isMasterDetailPlan(plan)) {
14732
- return masterDetailCanvas(plan.widgets);
14733
- }
14734
- return stackedCanvas(plan.widgets);
14735
- }
14736
- function isMasterDetailPlan(plan) {
14737
- const preset = (plan.layoutPreset ?? '').toLocaleLowerCase('en-US');
14738
- const hasPreset = preset.includes('master-detail') || preset.includes('master detail');
14739
- const hasSemanticRoles = plan.widgets.some((widget) => widget.role === 'master')
14740
- && plan.widgets.some((widget) => widget.role === 'detail');
14741
- return hasPreset || hasSemanticRoles;
14742
- }
14743
- function masterDetailCanvas(widgets) {
14744
- const master = widgets.find((widget) => widget.role === 'master') ?? widgets[0];
14745
- const details = widgets.filter((widget) => widget.key !== master.key);
14746
- const items = {};
14747
- let row = 1;
14748
- items[master.key] = {
14749
- col: 1,
14750
- row,
14751
- colSpan: 12,
14752
- rowSpan: preferredRowSpan(master),
14753
- };
14754
- row += items[master.key].rowSpan;
14755
- for (const widget of details) {
14756
- const rowSpan = preferredRowSpan(widget);
14757
- items[widget.key] = {
14758
- col: 1,
14759
- row,
14760
- colSpan: 12,
14761
- rowSpan,
14762
- };
14763
- row += rowSpan;
14764
- }
14765
- return defaultCanvas(items);
14766
- }
14767
- function stackedCanvas(widgets) {
14768
- const items = {};
14769
- let row = 1;
14770
- for (const widget of widgets) {
14771
- const rowSpan = preferredRowSpan(widget);
14772
- items[widget.key] = {
14773
- col: 1,
14774
- row,
14775
- colSpan: 12,
14776
- rowSpan,
14777
- };
14778
- row += rowSpan;
14779
- }
14780
- return defaultCanvas(items);
14781
- }
14782
- function defaultCanvas(items) {
14783
- return {
14784
- mode: 'grid',
14785
- columns: 12,
14786
- rowUnit: '80px',
14787
- gap: '16px',
14788
- autoRows: 'fixed',
14789
- items,
14790
- };
14791
- }
14792
- function preferredRowSpan(widget) {
14793
- const componentId = widget.componentId.toLocaleLowerCase('en-US');
14794
- if (componentId.includes('dynamic-form') || widget.role === 'detail')
14795
- return 8;
14796
- if (componentId.includes('table') || componentId.includes('list'))
14797
- return 7;
14798
- if (componentId.includes('chart'))
14799
- return 5;
14800
- if (componentId.includes('kpi') || componentId.includes('filter'))
14801
- return 2;
14802
- if (componentId.includes('rich-content'))
14803
- return 3;
14804
- return 4;
14805
- }
14806
15080
  function validateUiCompositionPlan(plan) {
14807
15081
  const diagnostics = [];
14808
15082
  const widgetKeys = new Set();
@@ -14866,6 +15140,7 @@ function validateUiCompositionPlan(plan) {
14866
15140
  validateGrouping(plan.grouping, widgetKeys, diagnostics);
14867
15141
  validateDeviceLayouts(plan.deviceLayouts, widgetKeys, diagnostics);
14868
15142
  validateSlotAssignments(plan.slotAssignments, widgetKeys, diagnostics);
15143
+ diagnostics.push(...validateUiCompositionPlanLayout(plan));
14869
15144
  return diagnostics;
14870
15145
  }
14871
15146
  function validateSelectionSync(selectionSync, widgetKeys, diagnostics, path) {
@@ -15529,6 +15804,67 @@ function clone(value) {
15529
15804
  }
15530
15805
  }
15531
15806
 
15807
+ /**
15808
+ * Fail-closed pre-apply attestation against the registry that will materialize the page.
15809
+ * It does not render widgets, execute links, call HTTP endpoints or persist configuration.
15810
+ */
15811
+ function preflightUiCompositionPlan(plan, registry, validator = new CompositionValidatorService()) {
15812
+ const compiled = compileUiCompositionPlan(plan);
15813
+ const compilerDiagnostics = compiled.diagnostics.map((diagnostic, index) => fromCompilerDiagnostic(diagnostic, index, !compiled.valid));
15814
+ if (!compiled.valid) {
15815
+ return {
15816
+ valid: false,
15817
+ page: null,
15818
+ diagnostics: compilerDiagnostics,
15819
+ };
15820
+ }
15821
+ if (!registry) {
15822
+ return {
15823
+ valid: false,
15824
+ page: null,
15825
+ diagnostics: [
15826
+ ...compilerDiagnostics,
15827
+ createAuthoringDiagnostic('ui-composition-plan:target-registry-required', 'UI_COMPOSITION_TARGET_REGISTRY_REQUIRED', 'The target ComponentMetadataRegistry is required before applying a UiCompositionPlan.', undefined, true, 'target-registry'),
15828
+ ],
15829
+ };
15830
+ }
15831
+ const links = (compiled.page.composition?.links || []);
15832
+ const semanticDiagnostics = validator.validatePage(compiled.page, {
15833
+ registry,
15834
+ links,
15835
+ });
15836
+ const diagnostics = [...compilerDiagnostics, ...semanticDiagnostics];
15837
+ const blocking = diagnostics.some((diagnostic) => diagnostic.blocking !== false
15838
+ && (diagnostic.severity === 'error' || diagnostic.severity === 'fatal'));
15839
+ return blocking
15840
+ ? { valid: false, page: null, diagnostics }
15841
+ : { valid: true, page: compiled.page, diagnostics };
15842
+ }
15843
+ function fromCompilerDiagnostic(diagnostic, index, blocking) {
15844
+ return createAuthoringDiagnostic(`ui-composition-plan:compiler:${index}:${diagnostic.code}:${diagnostic.path || 'page'}`, diagnostic.code, diagnostic.message, diagnostic.path, blocking, blocking ? 'document-validation' : 'layout-materialization');
15845
+ }
15846
+ function createAuthoringDiagnostic(id, code, message, path, blocking, stage) {
15847
+ return {
15848
+ id,
15849
+ code,
15850
+ severity: blocking ? 'error' : 'warning',
15851
+ phase: 'page-lint',
15852
+ message,
15853
+ summary: message,
15854
+ subject: {
15855
+ kind: 'page',
15856
+ path,
15857
+ },
15858
+ details: {
15859
+ provenance: 'ui-composition-plan-preflight',
15860
+ stage,
15861
+ },
15862
+ source: 'authoring',
15863
+ blocking,
15864
+ createdAt: new Date().toISOString(),
15865
+ };
15866
+ }
15867
+
15532
15868
  const RUNTIME_AUTHORING_METADATA_INPUTS = [
15533
15869
  'schemaVerification',
15534
15870
  'schemaEvidenceSource',
@@ -15685,25 +16021,32 @@ class PageBuilderAiAdapter {
15685
16021
  return this.applyPatch({ page: materializedPage }, 'agentic-authoring.compiled-form-patch');
15686
16022
  }
15687
16023
  async applyUiCompositionPlan(plan) {
15688
- const compiled = compileUiCompositionPlan(plan);
15689
- if (!compiled.valid) {
16024
+ const preflight = preflightUiCompositionPlan(plan, this.registry);
16025
+ if (!preflight.valid) {
15690
16026
  return {
15691
16027
  success: false,
15692
- error: compiled.diagnostics.map((diagnostic) => diagnostic.message).join('\n'),
15693
- warnings: compiled.diagnostics.map((diagnostic) => diagnostic.path
15694
- ? `${diagnostic.code} at ${diagnostic.path}`
16028
+ error: preflight.diagnostics.map((diagnostic) => diagnostic.subject.path
16029
+ ? `${diagnostic.code} at ${diagnostic.subject.path}: ${diagnostic.message}`
16030
+ : `${diagnostic.code}: ${diagnostic.message}`).join('\n'),
16031
+ warnings: preflight.diagnostics.map((diagnostic) => diagnostic.subject.path
16032
+ ? `${diagnostic.code} at ${diagnostic.subject.path}`
15695
16033
  : diagnostic.code),
16034
+ diagnostics: preflight.diagnostics,
15696
16035
  };
15697
16036
  }
15698
16037
  try {
15699
- const warnings = [];
16038
+ const warnings = preflight.diagnostics.map((diagnostic) => diagnostic.subject.path
16039
+ ? `${diagnostic.code} at ${diagnostic.subject.path}`
16040
+ : diagnostic.code);
15700
16041
  const current = this.getCurrentConfig();
15701
16042
  const next = this.normalizeConfigForRuntime({
15702
16043
  ...current,
15703
- page: this.clone(compiled.page),
16044
+ page: this.clone(preflight.page),
15704
16045
  }, warnings);
15705
16046
  this.applyConfig(next);
15706
- return warnings.length ? { success: true, warnings } : { success: true };
16047
+ return warnings.length
16048
+ ? { success: true, warnings, diagnostics: preflight.diagnostics }
16049
+ : { success: true, diagnostics: preflight.diagnostics };
15707
16050
  }
15708
16051
  catch (error) {
15709
16052
  const message = error instanceof Error ? error.message : 'Unknown error applying UI composition plan';
@@ -24178,11 +24521,20 @@ class DynamicPageBuilderComponent {
24178
24521
  async applyAgenticPreviewLocally(result) {
24179
24522
  const adapter = new PageBuilderAiAdapter(this.createAdapterHost(), this.componentMetadata);
24180
24523
  const snapshot = adapter.createSnapshot();
24181
- const applied = await (result.compiledFormPatch?.patch?.page
24182
- ? adapter.applyCompiledFormPatch(result.compiledFormPatch)
24183
- : result.uiCompositionPlan
24184
- ? adapter.applyUiCompositionPlan(result.uiCompositionPlan)
24185
- : adapter.applyCompiledFormPatch(result.compiledFormPatch));
24524
+ const applied = await (result.uiCompositionPlan
24525
+ ? adapter.applyUiCompositionPlan(result.uiCompositionPlan)
24526
+ : adapter.applyCompiledFormPatch(result.compiledFormPatch));
24527
+ if (applied.warnings?.length) {
24528
+ result.warnings = Array.from(new Set([...(result.warnings || []), ...applied.warnings]));
24529
+ }
24530
+ if (!applied.success && applied.diagnostics?.length) {
24531
+ result.failureCodes = Array.from(new Set([
24532
+ ...(result.failureCodes || []),
24533
+ ...applied.diagnostics
24534
+ .filter((diagnostic) => diagnostic.blocking !== false)
24535
+ .map((diagnostic) => diagnostic.code),
24536
+ ]));
24537
+ }
24186
24538
  if (!applied.success && this.isAgenticTableContractError(applied.error)) {
24187
24539
  await adapter.restoreSnapshot(snapshot);
24188
24540
  return {
@@ -24844,9 +25196,6 @@ class DynamicPageBuilderComponent {
24844
25196
  return value;
24845
25197
  }
24846
25198
  resolvePreviewCompiledFormPatch(preview) {
24847
- if (preview.compiledFormPatch?.patch?.page) {
24848
- return preview.compiledFormPatch;
24849
- }
24850
25199
  if (preview.uiCompositionPlan) {
24851
25200
  const planDiagnostics = this.toRecord(this.toRecord(preview.uiCompositionPlan)?.['diagnostics']);
24852
25201
  return {
@@ -24858,6 +25207,9 @@ class DynamicPageBuilderComponent {
24858
25207
  },
24859
25208
  };
24860
25209
  }
25210
+ if (preview.compiledFormPatch?.patch?.page) {
25211
+ return preview.compiledFormPatch;
25212
+ }
24861
25213
  return preview.compiledFormPatch;
24862
25214
  }
24863
25215
  focusCanvasWidget(widgetKey) {
@@ -26395,4 +26747,4 @@ function providePraxisPageBuilderMetadata() {
26395
26747
  * Generated bundle index. Do not edit.
26396
26748
  */
26397
26749
 
26398
- export { ComponentPaletteDialogComponent, ConfirmDialogComponent, ConnectionEditorComponent, DynamicPageBuilderComponent, DynamicPageConfigEditorComponent, FloatingToolbarComponent, PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS, PAGE_BUILDER_AI_CAPABILITIES, PAGE_BUILDER_COMPONENT_CONTEXT_PACK, PAGE_BUILDER_WIDGET_AI_CATALOGS, PLACEHOLDER, PRAXIS_PAGE_BUILDER_AUTHORING_MANIFEST, PRAXIS_PAGE_BUILDER_COMPONENT_METADATA, PageBuilderAgenticAuthoringService, PageConfigEditorComponent, TileToolbarComponent, WidgetShellEditorComponent, clearWidgetAiCatalogs, compileUiCompositionPlan, getPageAiCatalog, getWidgetAiCapabilities, providePageBuilderWidgetAiCatalogs, providePraxisPageBuilderMetadata, registerWidgetAiCatalog, registerWidgetAiCatalogs, resolveUiCompositionPlanTemplate, validateUiCompositionPlan };
26750
+ export { ComponentPaletteDialogComponent, ConfirmDialogComponent, ConnectionEditorComponent, DynamicPageBuilderComponent, DynamicPageConfigEditorComponent, FloatingToolbarComponent, PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS, PAGE_BUILDER_AI_CAPABILITIES, PAGE_BUILDER_COMPONENT_CONTEXT_PACK, PAGE_BUILDER_WIDGET_AI_CATALOGS, PLACEHOLDER, PRAXIS_PAGE_BUILDER_AUTHORING_MANIFEST, PRAXIS_PAGE_BUILDER_COMPONENT_METADATA, PageBuilderAgenticAuthoringService, PageConfigEditorComponent, TileToolbarComponent, WidgetShellEditorComponent, clearWidgetAiCatalogs, compileUiCompositionPlan, getPageAiCatalog, getWidgetAiCapabilities, preflightUiCompositionPlan, providePageBuilderWidgetAiCatalogs, providePraxisPageBuilderMetadata, registerWidgetAiCatalog, registerWidgetAiCatalogs, resolveUiCompositionPlanTemplate, validateUiCompositionPlan };