Skip to content

[v1.0][web_core][react] ComponentNode and useNodeView omit component metadata.extensions from resolved nodes and toJSON() #3469

Closed

Description

@josemontespg

Summary

When MessageProcessor.applyComponentUpdate processes a v1.0 component carrying metadata: { extensions: { ... } }, it stores metadata on ComponentModel.metadata (typescript/core/web_core/src/state/component-model.ts line 45).

However, when NodeResolver builds the reactive ComponentNode tree (typescript/core/web_core/src/resolution/component-node.ts and node-resolver.ts):

  1. ComponentNode (MutableComponentNode) has no metadata property or getter.
  2. ComponentNode.toJSON() (lines 213–226 of component-node.ts) serializes { id, type, ...props } and completely omits metadata (unlike ComponentModel.componentTree, which includes ...(this.metadata !== undefined ? {metadata: this.metadata} : {})).
  3. When ComponentModel.metadata is updated on an existing component (existing.metadata = metadata; existing.properties = properties; at message-processor.ts lines 1059–1060), if properties are shallow-equal (setProps in component-node.ts line 238), node.props does not emit and React views subscribed via useNodeView in @a2ui/react do not re-render on a metadata-only update.

Affected Component / Files

  • Repository commit: e9dbcc3 (main) and npm packages @a2ui/[email protected], @a2ui/[email protected]
  • File path(s):
    • typescript/core/web_core/src/resolution/component-node.ts (lines 50–119, 213–241)
    • typescript/core/web_core/src/resolution/node-resolver.ts (lines 380–450)
    • typescript/renderers/react/src/node-view.tsx (lines 207–266)

Steps to Reproduce / Evidence

import { MessageProcessor, NodeResolver, basicCatalog } from '@a2ui/web_core/v1_0';

const processor = new MessageProcessor([basicCatalog], undefined, { version: 'v1.0' });
processor.processMessages([
  {
    version: 'v1.0',
    createSurface: {
      surfaceId: 's1',
      catalogId: basicCatalog.id,
      components: [
        {
          id: 'root',
          component: 'Text',
          text: 'Hello',
          metadata: {
            extensions: {
              custom_theme: { variant: 'dark' },
            },
          },
        },
      ],
    },
  },
]);

const surface = processor.model.getSurface('s1');
const resolver = new NodeResolver(surface);
const rootNode = resolver.rootNode.peek();

console.log('ComponentModel.componentTree:', surface.componentsModel.get('root').componentTree);
// Includes: metadata: { extensions: { custom_theme: { variant: 'dark' } } }

console.log('ComponentNode.toJSON():', rootNode.toJSON());
// Actual output: { id: 'root', type: 'Text', text: 'Hello', variant: 'body' }
// `metadata` is completely missing from ComponentNode and rootNode.toJSON()!

Expected Behavior

  1. ComponentNode should expose metadata (or reactive metadata signal/property from context?.componentModel.metadata) and include metadata in ComponentNode.toJSON() when defined.
  2. Updating a component's metadata.extensions via updateComponents should notify NodeResolver / useNodeView subscribers even when component schema properties (text, variant, etc.) are unchanged.

Actual Behavior

ComponentNode omits metadata from its interface and toJSON(), and metadata-only updateComponents payloads do not trigger node.props updates when schema properties are unchanged.

Suggested Fix

Expose readonly metadata?: Record<string, unknown> on ComponentNode (backed by this.context?.componentModel.metadata), include metadata in MutableComponentNode.toJSON() when defined, and include metadata in NodeResolver's change detection when ComponentModel.onUpdated fires.

Activity

  1. added
    status: needs-triageauto-managed: https://github.com/a2ui-project/a2ui/blob/main/scripts/triage.mjs
    on Oct 22, 2026
  2. josemontespg commented on Oct 23, 2026

    @josemontespg
    CollaboratorAuthor

    Confirmed on main. ComponentNode (typescript/core/web_core/src/resolution/component-node.ts) currently omits metadata from the resolved node interface and toJSON(), and MutableComponentNode only checks shallowEqual on props so metadata-only updates do not notify subscribers. Closing this issue for now as a minor (P2) improvement since we do not have the capacity to prioritize it around the v1.0 launch.

  3. moved this from Todo to Done in A2UIon Oct 23, 2026
  4. moved this from Done to In Progress in A2UIon Oct 29, 2026
  5. added 3 commits that reference this issue on Oct 29, 2026
    472538a
    ec78bff
    9055207
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: needs-triageauto-managed: https://github.com/a2ui-project/a2ui/blob/main/scripts/triage.mjsv1-bug-bash

    Type

    No type

    Projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions