Nested shared types not syncing

I am trying to sync a nested yDoc using y-webrtc but getting unexpected results when nesting

Scenario 1 → Working as expected
Creating shared types at root level → Stackblitz link
Relevant code

const ydoc = new Y.Doc();
const elements = ydoc.getArray('elements');
const assets = ydoc.getMap('assets');

...
React.useEffect(() => {
    if (!api) return;

    const binding = new ExcalidrawBinding(
      elements as any,  // Passing elements to an external binding
      api,
      provider.awareness
    );
    setBindings(binding);
    const assetBinding = new ExcalidrawAssetsBinding(assets, api);

    return () => {
      setBindings(null);
      binding.destroy();
      assetBinding.destroy();
    };
  }, [api]);

When two links are opened the documents sync correctly between them

Scenario 2 → Not working as expected
Creating nested shared types → Stackblitz link
Relevant code

const ydoc = new Y.Doc();
const root = ydoc.getMap('excalidraw');
const elements = new Y.Array();
const assets = new Y.Map();
root.set('elements', elements);
root.set('assets', assets);

...
React.useEffect(() => {
    if (!api) return;

    const binding = new ExcalidrawBinding(
      elements as any,  // Passing elements to an external binding
      api,
      provider.awareness
    );
    setBindings(binding);
    const assetBinding = new ExcalidrawAssetsBinding(assets, api);

    return () => {
      setBindings(null);
      binding.destroy();
      assetBinding.destroy();
    };
  }, [api]);

As soon as the 2nd instance of the link is opened, it crashes with an error in console.
I noticed the following behavior in the 2nd peer

console.log(elements.length)  // prints 0, even though there are some elements in the document (from first peer)
console.log(elements.doc.getMap('excalidraw').get("elements").length)  // prints 1 (correct)
console.log(elements == elements.doc.getMap('excalidraw').get("elements")) // Prints false 

Why is nesting the types not working but creating at root level is?

Every time you run the second scenario, you overwrite elements and assets.

Example code to clarify.

// First time you run the code
const elements1 = new Y.Array()
root.set('elements', elements1)

// second time you run the code, elements is overwritten with a new type
const elements2 = new Y.Array()
root.set('elements', elements2) // implicitly, this triggers elements1.destroy(), as this value is overwritten.

The problem is that the first binding still uses the first elements1 reference, which has been destroyed.

The root type access ydoc.getArray('elements') is preferable here, because it never overwrites data.

Technically, you could also update the elements reference when root is changed (root.observe(() => { elements = root.get('elements') })). But it would be better to only overwrite data when really necessary. Use the root-types instead for this use-case.

Ohk, makes sense.
When I was using websockets before didn’t face this as the initialization code was on the server which ran only once whereas in webrtc approach it runs multiple times. Thanks for the clarification