Skip to content

Track catalog transitions - #173

Open
jgindin wants to merge 18 commits into
mainfrom
track-catalog-transitions
Open

Track catalog transitions#173
jgindin wants to merge 18 commits into
mainfrom
track-catalog-transitions

Conversation

@jgindin

@jgindin jgindin commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Description

Passive Handshake Model & User Draft Protection

  • Refactors StateSync so that A2UI_CATALOG capability announcements act as passive handshakes rather than destructive transition triggers.
  • Introduces an isDraftModified lock to protect active user edits, sidecar-injected drafts, and transcript replays from being clobbered by asynchronous catalog handshakes.
  • Resets the modification lock upon explicit renderer changes (selectedRendererId$) to properly synchronize new default renderer templates.
  • Decouples initial draft initialization from shared URL payloads to guarantee clean session resets.

Pre-launch Checklist

  • I signed the [CLA].
  • I read the [Contributors Guide].
  • I read the [Style Guide].
  • I have added updates to the [CHANGELOG].
  • I updated/added relevant documentation.
  • My code changes (if any) have tests.
  • If my branch is on fork, I have verified that scripts/e2e_test.sh passes.

If you need help, consider asking for advice on the [discussion board].

jgindin added 18 commits August 18, 2026 12:17
Create SafeUrlValidatorService for http/https validation.
Create DomainOriginVerificationService for strict iframe networking validation.
Wire bypassSecurityTrustResourceUrl inside rendered-frame.ts through the rigorous URL validator.
Swap the check in preview-bridge.ts for the strict origin verification.
Fix LLM concurrency in ChatCoordinator submitPrompt.
Fix Monaco model.dispose() in a2ui-composer-monaco-editor.
Inject takeUntilDestroyed in api-key-selector.ts and renderer-selector.ts.
Delete debug/mock-rules/ entirely.
Rip out console.error patch hacks from ChatCoordinator.
Delete obsolete storage key ACTIVE_DRAFT.
…ks into decoupled targets accurately abandoning monolithic arrays globally
…mentations and un-deferred webrtc layout code gracefully
…ngestion

- Implement TrackEventDirective applying declarative tracking boundaries natively.
- Construct FileIngestionService strictly leveraging @angular/cdk/clipboard utilities.
- Construct ShareService cleanly encapsulating clipboard interactions.
- Sweep all active standalone UI components throughout the app, converting default ChangeDetection behavior to ChangeDetectionStrategy.OnPush.
- Strip FileReader native accesses from ChatPanel into the FileIngestionService.
- Swap template tracking to the directive.
- Rip out the legacy shareDesign() bloated component implementation comprehensively.
- Delete deprecated inner test asserts and old inline code.
When a design link is shared and loaded, cleanSharedA2uiUrl removes
the 'a2ui', 'renderer', and 'rendererId' parameters from the window
hash and search parameters using history.replaceState so they do
not linger in the address bar.

Additionally, update StartupResolution to map queryRendererUrl to
its corresponding static or custom renderer configuration and persist
allowed unknown URLs into LocalStorage. Update Settings view to
default to the active renderer selection instead of an unselected
state. Include rendererId alongside renderer in share URL hashes.
Update tryParseJsonArray in shell utils/json.ts to parse:
- Standard JSON arrays ([...])
- Single JSON objects ({...} -> [obj])
- JSON Lines ({...}\n{...} -> [obj1, obj2, ...])

Update RawFrame to use tryParseJsonArray when parsing layout JSON.
Update ChatCleaner to validate layout snapshots using isLayoutArray.
Add unit tests covering JSON Lines, single objects, and edge cases.
Refactor StateSync to treat A2UI_CATALOG capability announcements as
passive handshakes rather than destructive transition triggers:
- Track isDraftModified to protect sidecar injected drafts, transcript
  replays, and user edits from asynchronous handshake clobbering.
- Handle renderer switches via selectedRendererId$ by resetting the
  modification lock to synchronize new default renderer templates.
- Filter catalog streams safely to support custom renderers without
  formal catalog IDs.
- Decouple getInitialDraft from sharedA2uiPayload to ensure clean
  resets in shared URL sessions.
@github-actions

Copy link
Copy Markdown
Contributor

⚡ A2UI Composer PR Preview

Your automated preview is successfully live (commit 144016d):
👉 Launch PR Preview

Note: This environment will be wiped automatically when the PR is merged or closed.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the chat and workspace shell by modularizing payload parsing, file ingestion, error formatting, screenshot capture, and sharing services, while also removing the deprecated mock rules debug panel. The review feedback identifies a critical bug in the new sanitizeValue function where rules and mock* properties are not filtered out, a recommendation to harden tryParseJsonArray against nullish inputs, and the usage of the deprecated substr method in the Monaco editor component.

Comment on lines +258 to +260
for (const [key, propVal] of Object.entries(obj)) {
cleaned[key] = sanitizeValue(propVal);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The new implementation of sanitizeValue completely omitted the filtering logic for rules and mock* properties. This causes mock configurations and rules to leak into the production payload, which can lead to validation failures or security/privacy issues. Additionally, the unit test removes mock* and rules properties in a2ui-payload-parser.spec.ts is passing because it only asserts that valid properties are preserved, but fails to assert that mock/rules properties are actually removed.

  for (const [key, propVal] of Object.entries(obj)) {
    if (key === 'rules' || /^mock/i.test(key)) {
      continue;
    }
    cleaned[key] = sanitizeValue(propVal);
  }

Comment on lines 24 to +28
export function tryParseJsonArray(content: string): unknown[] | null {
const trimmed = content.trim();
if (trimmed.length === 0) {
return null;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Per the general rules, string processing utility methods should be hardened with guard clauses to safely handle nullish or undefined inputs by returning safe defaults, and corresponding unit tests should be added to verify resilience against nullish values. Please add a guard clause to handle nullish/undefined content inputs.

Suggested change
export function tryParseJsonArray(content: string): unknown[] | null {
const trimmed = content.trim();
if (trimmed.length === 0) {
return null;
}
export function tryParseJsonArray(content: string | null | undefined): unknown[] | null {
if (!content) {
return null;
}
const trimmed = content.trim();
References
  1. Harden string processing utility methods with guard clauses to safely handle nullish or undefined inputs by returning safe defaults, and ensure corresponding unit tests are added to verify resilience against nullish values.

styleUrl: './monaco-editor.scss',
})
export class MonacoEditor {
private readonly layoutModelUriStr = `a2ui://layout-${Math.random().toString(36).substr(2, 9)}.json`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

String.prototype.substr is deprecated. Please use slice or substring instead to ensure long-term compatibility and adhere to modern JavaScript standards.

Suggested change
private readonly layoutModelUriStr = `a2ui://layout-${Math.random().toString(36).substr(2, 9)}.json`;
private readonly layoutModelUriStr = `a2ui://layout-${Math.random().toString(36).slice(2, 11)}.json`;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant