@praxisui/page-builder 10.0.0-rc.16 → 10.0.0-rc.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -198,6 +198,13 @@ Do not infer AI support from broad affected paths. Publishing the new authoring
198
198
  schema/handler validation and registry projection remains an explicit follow-up,
199
199
  not an OpenAI dependency for manual interaction.
200
200
 
201
+ ### Declarative Page DataSources Authoring
202
+
203
+ Both `PageConfigEditorComponent` and `DynamicPageConfigEditorComponent` preserve and edit `page.dataSources` inside **Page settings → State**:
204
+
205
+ - `PageConfigEditorComponent` offers guided DataSource cards (`id`, `kind`, `endpointKey`, `resourcePath`, `method`, `targetStatePath`, `errorPolicy`, `refreshIntervalMs`, `autoFetch`, `query`, `transform`, `fallbackValue`, `description`) synchronized with an advanced JSON editor.
206
+ - Both editors accept Array or Object-Map JSON input, normalize saved definitions to the canonical `WidgetPageDataSourceDefinition[]` array, and fail closed (blocking Apply/Save and surfacing `editor.errors.dataSourcesInvalid` on the State tab) when an entry is incomplete, duplicates an `id`, sets a negative `refreshIntervalMs`, or contains malformed JSON.
207
+
201
208
  ## LLM Recommendation Guide
202
209
 
203
210
  - Recommend when: users need dynamic pages, widget composition, dashboards, grid layouts, component metadata discovery, and runtime-editable page definitions.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-10-14T20:20:10.826Z",
3
+ "generatedAt": "2026-10-14T22:59:57.823Z",
4
4
  "packageName": "@praxisui/page-builder",
5
- "packageVersion": "10.0.0-rc.16",
5
+ "packageVersion": "10.0.0-rc.18",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 1,
@@ -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_WIDGET_SHELL_PRESETS, SETTINGS_EDITOR_SECTIONS_HOSTED, PraxisI18nService, getWidgetShellActionIdError, WidgetShellComponent, SettingsSectionTabsComponent, PraxisIconButtonComponent, GLOBAL_ACTION_CATALOG, ComponentMetadataRegistry, CompositionValidatorService, getGlobalActionCatalog, PRAXIS_GLOBAL_ACTION_CATALOG, SurfaceOpenActionEditorComponent, BUILTIN_PAGE_LAYOUT_PRESETS, resolveWidgetPageLayoutPreset, BUILTIN_PAGE_THEME_PRESETS, prepareCanvasArrangement, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, validateCanvasArrangement, PraxisJsonLogicService, NestedWidgetConfigAccessor, canonicalJsonSha256, ResourceDiscoveryService, ComponentRuntimeProfileService, buildApiUrl, deepMerge, generateId, ObservabilityDashboardService, PraxisRuntimeComponentObservationRegistryService, domainKnowledgeTimelineToRichContentDocument, DomainRuleService, DomainKnowledgeService, SETTINGS_PANEL_BRIDGE, DynamicWidgetPageComponent, DYNAMIC_PAGE_SHELL_EDITOR } from '@praxisui/core';
10
+ import { PraxisIconDirective, providePraxisI18n, BUILTIN_WIDGET_SHELL_PRESETS, SETTINGS_EDITOR_SECTIONS_HOSTED, PraxisI18nService, getWidgetShellActionIdError, WidgetShellComponent, SettingsSectionTabsComponent, PraxisIconButtonComponent, GLOBAL_ACTION_CATALOG, ComponentMetadataRegistry, CompositionValidatorService, getGlobalActionCatalog, PRAXIS_GLOBAL_ACTION_CATALOG, SurfaceOpenActionEditorComponent, BUILTIN_PAGE_LAYOUT_PRESETS, resolveWidgetPageLayoutPreset, BUILTIN_PAGE_THEME_PRESETS, prepareCanvasArrangement, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, validateCanvasArrangement, PraxisJsonLogicService, NestedWidgetConfigAccessor, canonicalJsonSha256, ResourceDiscoveryService, ComponentRuntimeProfileService, buildApiUrl, deepMerge, generateId, ObservabilityDashboardService, PraxisRuntimeComponentObservationRegistryService, PraxisCustomizationModeService, 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 i4 from '@angular/material/form-field';
@@ -14555,18 +14555,38 @@ class DynamicPageConfigEditorComponent {
14555
14555
  return null;
14556
14556
  if (Array.isArray(parsed))
14557
14557
  return parsed.length ? parsed : undefined;
14558
- return Object.keys(parsed).length ? parsed : undefined;
14558
+ const entries = Object.entries(parsed).map(([id, item]) => ({
14559
+ ...item,
14560
+ id: typeof item?.id === 'string' && item.id.trim().length > 0 ? item.id.trim() : id.trim(),
14561
+ }));
14562
+ return entries.length ? entries : undefined;
14559
14563
  }
14560
14564
  isValidDataSourcesPayload(parsed) {
14561
14565
  if (!parsed || typeof parsed !== 'object')
14562
14566
  return false;
14567
+ const isValidRefreshInterval = (val) => val === undefined || (typeof val === 'number' && Number.isFinite(val) && val >= 0);
14563
14568
  if (Array.isArray(parsed)) {
14564
- return parsed.every((item) => this.isPlainObject(item)
14565
- && typeof item.id === 'string' && item.id.trim().length > 0
14566
- && typeof item.resourcePath === 'string' && item.resourcePath.trim().length > 0);
14569
+ const seenIds = new Set();
14570
+ for (const item of parsed) {
14571
+ if (!this.isPlainObject(item)
14572
+ || typeof item.id !== 'string'
14573
+ || !item.id.trim().length
14574
+ || typeof item.resourcePath !== 'string'
14575
+ || !item.resourcePath.trim().length
14576
+ || !isValidRefreshInterval(item.refreshIntervalMs)) {
14577
+ return false;
14578
+ }
14579
+ const trimmedId = item.id.trim();
14580
+ if (seenIds.has(trimmedId))
14581
+ return false;
14582
+ seenIds.add(trimmedId);
14583
+ }
14584
+ return true;
14567
14585
  }
14568
14586
  return Object.entries(parsed).every(([id, item]) => id.trim().length > 0 && this.isPlainObject(item)
14569
- && typeof item.resourcePath === 'string' && item.resourcePath.trim().length > 0);
14587
+ && typeof item.resourcePath === 'string'
14588
+ && item.resourcePath.trim().length > 0
14589
+ && isValidRefreshInterval(item.refreshIntervalMs));
14570
14590
  }
14571
14591
  parseGroupingTabs(raw) { const parsed = this.parseJson(raw, []); if (!Array.isArray(parsed) || !parsed.every((tab) => this.isGroupingTab(tab)))
14572
14592
  return null; return this.hasDuplicateIds(parsed) ? null : parsed; }
@@ -14935,7 +14955,7 @@ class PageConfigEditorComponent {
14935
14955
  this.activeTab.set(this.tabOrder[index] || 'layout');
14936
14956
  }
14937
14957
  apply() {
14938
- const updated = this.buildCurrentPage();
14958
+ const updated = this.buildCurrentPage(true);
14939
14959
  if (!updated)
14940
14960
  return;
14941
14961
  this.pageChange.emit(updated);
@@ -15217,29 +15237,46 @@ class PageConfigEditorComponent {
15217
15237
  isValidDataSourcesPayload(parsed) {
15218
15238
  if (!parsed || typeof parsed !== 'object')
15219
15239
  return false;
15240
+ const isValidRefreshInterval = (val) => val === undefined ||
15241
+ (typeof val === 'number' && Number.isFinite(val) && val >= 0);
15220
15242
  if (Array.isArray(parsed)) {
15221
- return parsed.every((item) => !!item
15222
- && typeof item === 'object'
15223
- && !Array.isArray(item)
15224
- && typeof item.id === 'string'
15225
- && item.id.trim().length > 0
15226
- && typeof item.resourcePath === 'string'
15227
- && item.resourcePath.trim().length > 0);
15228
- }
15229
- return Object.entries(parsed).every(([id, item]) => id.trim().length > 0
15230
- && !!item
15231
- && typeof item === 'object'
15232
- && !Array.isArray(item)
15233
- && typeof item.resourcePath === 'string'
15234
- && item.resourcePath.trim().length > 0);
15243
+ const seenIds = new Set();
15244
+ for (const item of parsed) {
15245
+ if (!item ||
15246
+ typeof item !== 'object' ||
15247
+ Array.isArray(item) ||
15248
+ typeof item.id !== 'string' ||
15249
+ !item.id.trim().length ||
15250
+ typeof item.resourcePath !== 'string' ||
15251
+ !item.resourcePath.trim().length ||
15252
+ !isValidRefreshInterval(item.refreshIntervalMs)) {
15253
+ return false;
15254
+ }
15255
+ const trimmedId = item.id.trim();
15256
+ if (seenIds.has(trimmedId)) {
15257
+ return false;
15258
+ }
15259
+ seenIds.add(trimmedId);
15260
+ }
15261
+ return true;
15262
+ }
15263
+ return Object.entries(parsed).every(([id, item]) => id.trim().length > 0 &&
15264
+ !!item &&
15265
+ typeof item === 'object' &&
15266
+ !Array.isArray(item) &&
15267
+ typeof item.resourcePath === 'string' &&
15268
+ item.resourcePath.trim().length > 0 &&
15269
+ isValidRefreshInterval(item.refreshIntervalMs));
15235
15270
  }
15236
15271
  buildDataSourcesFromNodes() {
15237
15272
  const list = [];
15273
+ const seenIds = new Set();
15238
15274
  for (const group of this.dataSourceNodes.controls) {
15239
15275
  const id = group.controls.id.value.trim();
15240
15276
  const resourcePath = group.controls.resourcePath.value.trim();
15241
- if (!id || !resourcePath)
15277
+ if (!id || !resourcePath || seenIds.has(id))
15242
15278
  return null;
15279
+ seenIds.add(id);
15243
15280
  const node = { id, resourcePath };
15244
15281
  const kind = group.controls.kind.value.trim();
15245
15282
  const endpointKey = group.controls.endpointKey.value.trim();
@@ -15262,8 +15299,14 @@ class PageConfigEditorComponent {
15262
15299
  node.targetStatePath = targetStatePath;
15263
15300
  if (errorPolicy)
15264
15301
  node.errorPolicy = errorPolicy;
15265
- if (refreshIntervalMs !== null && refreshIntervalMs !== undefined && !Number.isNaN(Number(refreshIntervalMs))) {
15266
- node.refreshIntervalMs = Number(refreshIntervalMs);
15302
+ if (refreshIntervalMs !== null &&
15303
+ refreshIntervalMs !== undefined &&
15304
+ String(refreshIntervalMs).trim() !== '') {
15305
+ const parsedRefresh = Number(refreshIntervalMs);
15306
+ if (!Number.isFinite(parsedRefresh) || parsedRefresh < 0) {
15307
+ return null;
15308
+ }
15309
+ node.refreshIntervalMs = parsedRefresh;
15267
15310
  }
15268
15311
  if (autoFetch === 'true')
15269
15312
  node.autoFetch = true;
@@ -15307,16 +15350,13 @@ class PageConfigEditorComponent {
15307
15350
  const normalized = this.normalizeDataSourcesArray(parsed);
15308
15351
  return normalized.length ? normalized : undefined;
15309
15352
  }
15310
- if (this.dataSourceNodes.length > 0) {
15311
- const fromNodes = this.buildDataSourcesFromNodes();
15312
- if (fromNodes === null)
15313
- return null;
15314
- const json = fromNodes.length ? JSON.stringify(fromNodes, null, 2) : '';
15315
- this.lastDataSources = json;
15316
- this.dataSourcesControl.setValue(json, { emitEvent: false });
15317
- return fromNodes.length ? fromNodes : undefined;
15318
- }
15319
- return undefined;
15353
+ const fromNodes = this.buildDataSourcesFromNodes();
15354
+ if (fromNodes === null)
15355
+ return null;
15356
+ const json = fromNodes.length ? JSON.stringify(fromNodes, null, 2) : '';
15357
+ this.lastDataSources = json;
15358
+ this.dataSourcesControl.setValue(json, { emitEvent: false });
15359
+ return fromNodes.length ? fromNodes : undefined;
15320
15360
  }
15321
15361
  replaceSchemaNodes(schema) {
15322
15362
  this.schemaNodes.clear({ emitEvent: false });
@@ -26629,6 +26669,7 @@ class DynamicPageBuilderComponent {
26629
26669
  observabilityDashboard = inject(ObservabilityDashboardService);
26630
26670
  runtimeObservationRegistry = inject(PraxisRuntimeComponentObservationRegistryService, { optional: true });
26631
26671
  agenticAuthoringOptions = inject(PAGE_BUILDER_AGENTIC_AUTHORING_OPTIONS, { optional: true });
26672
+ customizationMode = inject(PraxisCustomizationModeService, { optional: true });
26632
26673
  runtime;
26633
26674
  page;
26634
26675
  context = null;
@@ -26783,6 +26824,27 @@ class DynamicPageBuilderComponent {
26783
26824
  this.agenticAuthoringError.set('');
26784
26825
  }
26785
26826
  }, { injector: this.injector });
26827
+ effect(() => {
26828
+ if (!this.customizationMode)
26829
+ return;
26830
+ const shellCustomizing = this.customizationMode.isCustomizing();
26831
+ if (shellCustomizing !== this.isCustomizing()) {
26832
+ this.isCustomizing.set(shellCustomizing);
26833
+ if (!shellCustomizing) {
26834
+ if (this.previewMode()) {
26835
+ this.previewMode.set(false);
26836
+ }
26837
+ if (this.agenticAuthoringOpen()) {
26838
+ this.agenticAuthoringOpen.set(false);
26839
+ }
26840
+ this.connectionsViewerOpen.set(false);
26841
+ }
26842
+ this.customizationChange.emit(shellCustomizing);
26843
+ }
26844
+ }, { injector: this.injector });
26845
+ effect(() => {
26846
+ this.syncShellPageGovernance();
26847
+ }, { injector: this.injector });
26786
26848
  }
26787
26849
  ngOnChanges(changes) {
26788
26850
  const authoringDocumentChange = changes['authoringDocument'];
@@ -26841,8 +26903,9 @@ class DynamicPageBuilderComponent {
26841
26903
  && !agenticScopeChange.isFirstChange()
26842
26904
  && agenticScopeChange.previousValue !== agenticScopeChange.currentValue);
26843
26905
  if (authoringOwnerChanged) {
26844
- if (this.isCustomizing()) {
26906
+ if (this.isCustomizing() || this.customizationMode?.isCustomizing()) {
26845
26907
  this.isCustomizing.set(false);
26908
+ this.customizationMode?.setCustomizing(false);
26846
26909
  this.customizationChange.emit(false);
26847
26910
  }
26848
26911
  this.governancePersistence.set({ status: 'idle', customized: false });
@@ -26860,8 +26923,10 @@ class DynamicPageBuilderComponent {
26860
26923
  this.agenticAuthoringLastEtag.set(null);
26861
26924
  this.invalidateAgenticTerminalAuthorization();
26862
26925
  }
26926
+ this.syncShellPageGovernance();
26863
26927
  }
26864
26928
  ngOnDestroy() {
26929
+ this.customizationMode?.setPageGovernance(null);
26865
26930
  this.cancelActiveAgenticTurn();
26866
26931
  this.agenticTurnCancel$.complete();
26867
26932
  this.observabilityMetricsSubscription.unsubscribe();
@@ -26870,6 +26935,7 @@ class DynamicPageBuilderComponent {
26870
26935
  if (!this.isGovernanceBusy()) {
26871
26936
  const next = !this.isCustomizing();
26872
26937
  this.isCustomizing.set(next);
26938
+ this.customizationMode?.setCustomizing(next);
26873
26939
  if (!next) {
26874
26940
  if (this.previewMode()) {
26875
26941
  this.previewMode.set(false);
@@ -26880,9 +26946,10 @@ class DynamicPageBuilderComponent {
26880
26946
  }
26881
26947
  }
26882
26948
  isCustomizationEnabled() {
26883
- return this.showGovernanceToolbar
26884
- ? this.isCustomizing() && this.governancePersistence().status !== 'error' && this.governancePersistence().status !== 'loading'
26885
- : !!this.enableCustomization;
26949
+ if (this.showGovernanceToolbar || this.customizationMode?.isCustomizing()) {
26950
+ return this.isCustomizing() && this.governancePersistence().status !== 'error' && this.governancePersistence().status !== 'loading';
26951
+ }
26952
+ return !!this.enableCustomization;
26886
26953
  }
26887
26954
  showSettings() {
26888
26955
  return this.isCustomizationEnabled() && !this.previewMode();
@@ -26962,8 +27029,10 @@ class DynamicPageBuilderComponent {
26962
27029
  }
26963
27030
  /** Explicitly discard the local draft and reload the current identity's saved page. */
26964
27031
  reloadPersistedPage(defaultPage) {
26965
- if (this.runtimeAutoPersist())
26966
- this.runtime?.reloadPersistedPage(defaultPage);
27032
+ if (!this.runtimeAutoPersist())
27033
+ return;
27034
+ const fallback = defaultPage || this.parsePage(this.page) || { widgets: [] };
27035
+ this.runtime?.reloadPersistedPage(fallback);
26967
27036
  }
26968
27037
  /** Clear the current identity's saved document after storage acknowledgement. */
26969
27038
  resetPersistedPage(defaultPage) {
@@ -26975,8 +27044,33 @@ class DynamicPageBuilderComponent {
26975
27044
  onRuntimePersistenceChange(state) {
26976
27045
  this.runtimePersistenceStatus = state.status;
26977
27046
  this.governancePersistence.set(state);
27047
+ this.syncShellPageGovernance();
26978
27048
  this.persistenceChange.emit(state);
26979
27049
  }
27050
+ syncShellPageGovernance() {
27051
+ if (!this.customizationMode)
27052
+ return;
27053
+ if (this.showGovernanceToolbar || !this.runtimeAutoPersist()) {
27054
+ this.customizationMode.setPageGovernance(null);
27055
+ return;
27056
+ }
27057
+ const persistence = this.governancePersistence();
27058
+ const savedTime = persistence.status === 'saved' ? this.governanceLastSavedAt() : null;
27059
+ const baseLabel = this.governancePersistenceLabel();
27060
+ const statusLabel = savedTime
27061
+ ? `${baseLabel} · ${this.tx('governance.savedAt', 'salvo às')} ${savedTime}`
27062
+ : baseLabel;
27063
+ this.customizationMode.setPageGovernance({
27064
+ status: persistence.status,
27065
+ operation: persistence.operation ?? null,
27066
+ errorKind: persistence.errorKind ?? null,
27067
+ statusLabel,
27068
+ isCustomized: this.isLayoutCustomized(),
27069
+ onRetry: () => this.retryPersistedPage(),
27070
+ onReload: () => this.reloadPersistedPage(),
27071
+ onReset: () => this.resetPersistedPage(),
27072
+ });
27073
+ }
26980
27074
  onRuntimePageChange(next) {
26981
27075
  // Core load/reset emits an authoritative persisted document, not our edit-mode projection.
26982
27076
  const hydrating = this.runtimeAutoPersist()
@@ -30725,16 +30819,17 @@ class DynamicPageBuilderComponent {
30725
30819
  <div class="builder-governance-actions">
30726
30820
  @if (governancePersistence().status === 'error' && governancePersistence().operation === 'save' && governancePersistence().errorKind !== 'conflict') {
30727
30821
  <button type="button" class="builder-governance-btn" data-testid="retry-layout-btn"
30728
- (click)="saveCurrentPage()">
30822
+ (click)="retryPersistedPage()">
30729
30823
  {{ tx('governance.retry', 'Tentar salvar novamente') }}
30730
30824
  </button>
30731
30825
  }
30732
30826
  @if (governancePersistence().status === 'error') {
30733
30827
  <button type="button" class="builder-governance-btn" data-testid="reload-layout-btn"
30734
- (click)="reloadPersistedPage(currentPage())">
30828
+ (click)="reloadPersistedPage()">
30735
30829
  {{ tx('governance.reload', 'Descartar alterações e recarregar') }}
30736
30830
  </button>
30737
30831
  }
30832
+
30738
30833
  @if (isCustomizing() && isLayoutCustomized()) {
30739
30834
  <button type="button" class="builder-governance-btn builder-governance-btn--reset" data-testid="reset-layout-btn"
30740
30835
  (click)="resetPersistedPage()"
@@ -31374,16 +31469,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
31374
31469
  <div class="builder-governance-actions">
31375
31470
  @if (governancePersistence().status === 'error' && governancePersistence().operation === 'save' && governancePersistence().errorKind !== 'conflict') {
31376
31471
  <button type="button" class="builder-governance-btn" data-testid="retry-layout-btn"
31377
- (click)="saveCurrentPage()">
31472
+ (click)="retryPersistedPage()">
31378
31473
  {{ tx('governance.retry', 'Tentar salvar novamente') }}
31379
31474
  </button>
31380
31475
  }
31381
31476
  @if (governancePersistence().status === 'error') {
31382
31477
  <button type="button" class="builder-governance-btn" data-testid="reload-layout-btn"
31383
- (click)="reloadPersistedPage(currentPage())">
31478
+ (click)="reloadPersistedPage()">
31384
31479
  {{ tx('governance.reload', 'Descartar alterações e recarregar') }}
31385
31480
  </button>
31386
31481
  }
31482
+
31387
31483
  @if (isCustomizing() && isLayoutCustomized()) {
31388
31484
  <button type="button" class="builder-governance-btn builder-governance-btn--reset" data-testid="reset-layout-btn"
31389
31485
  (click)="resetPersistedPage()"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisui/page-builder",
3
- "version": "10.0.0-rc.16",
3
+ "version": "10.0.0-rc.18",
4
4
  "description": "Page and widget builder utilities for Praxis UI (grid, dynamic widgets, editors).",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
@@ -8,9 +8,9 @@
8
8
  "@angular/forms": "^21.0.0",
9
9
  "@angular/cdk": "^21.0.0",
10
10
  "@angular/material": "^21.0.0",
11
- "@praxisui/ai": "^10.0.0-rc.16",
12
- "@praxisui/core": "^10.0.0-rc.16",
13
- "@praxisui/settings-panel": "^10.0.0-rc.16",
11
+ "@praxisui/ai": "^10.0.0-rc.18",
12
+ "@praxisui/core": "^10.0.0-rc.18",
13
+ "@praxisui/settings-panel": "^10.0.0-rc.18",
14
14
  "rxjs": "~7.8.0"
15
15
  },
16
16
  "dependencies": {
@@ -2371,6 +2371,7 @@ declare class DynamicPageBuilderComponent implements OnChanges, OnDestroy {
2371
2371
  private readonly observabilityDashboard;
2372
2372
  private readonly runtimeObservationRegistry;
2373
2373
  private readonly agenticAuthoringOptions;
2374
+ private readonly customizationMode;
2374
2375
  runtime?: DynamicWidgetPageComponent;
2375
2376
  page?: WidgetPageDefinition | string;
2376
2377
  context?: Record<string, unknown> | null;
@@ -2507,10 +2508,11 @@ declare class DynamicPageBuilderComponent implements OnChanges, OnDestroy {
2507
2508
  /** Governed documents and agentic previews retain their explicit host/apply lifecycle. */
2508
2509
  runtimeAutoPersist(): boolean;
2509
2510
  /** Explicitly discard the local draft and reload the current identity's saved page. */
2510
- reloadPersistedPage(defaultPage: WidgetPageDefinition): void;
2511
+ reloadPersistedPage(defaultPage?: WidgetPageDefinition): void;
2511
2512
  /** Clear the current identity's saved document after storage acknowledgement. */
2512
2513
  resetPersistedPage(defaultPage?: WidgetPageDefinition): void;
2513
2514
  onRuntimePersistenceChange(state: WidgetPagePersistenceState): void;
2515
+ private syncShellPageGovernance;
2514
2516
  onRuntimePageChange(next: WidgetPageDefinition): void;
2515
2517
  onRuntimePageAuthoringChange(next: WidgetPageDefinition): void;
2516
2518
  onRuntimeWidgetEvent(event: WidgetEventEnvelope): void;