observeDeep() not working as I expected with Y.Array

I’ve tracked down what I think is an issue with observeDeep() and Y.Array updates.

I’ve put together the following code which shows the issue and the output when run.

I’m using YJS Version: 13.5.41 however I’ve also tested it on 13.5.43 and see the same issue.

The issue is when I add the first child docToAdd2, I don’t see observeDeep() yArrayCollection yArray yEvent.

/** @package

    yjs-observe.js
    
    Author: NEVILLE FRANKS
    Created: NF  12/12/2022 4:50:10 PM
	Last change: NF 12/12/2022 6:11:32 PM
*/

import * as Y from 'yjs'


let ydocRoot, yMapCollection, yArrayCollection;


function createYJSTYpes(){

    ydocRoot = new Y.Doc()

    /* Simplify and skip yMapCollection
    yMapCollection = ydocRoot.getMap( 'yMC' )
    yMapCollection.observeDeep( fnObserver.bind( yMapCollection ) )
    */

    yArrayCollection = ydocRoot.getArray( 'yAC' )
    yArrayCollection.observeDeep( fnObserver.bind( yArrayCollection ) )
}


function addItem( yIndex, docToAdd ){

    return new Promise( ( resolve, reject ) => {

        ydocRoot.transact( () => {

            const id = docToAdd.id
        
            // 1) Create a new yMapCollection entry
            // yMapCollection.set( id, docToAdd )

            let added = false

            // 2) add docToAdd.id to yArrayCollection. if yIndex is undefined create a create a new top level item else create a child item
            if ( yIndex != undefined ){
                if ( yArrayCollection.get( yIndex ) ){
                    newChildTreeNode( { ymap: yArrayCollection.get( yIndex ), id } )
                    added = true
                }else
                    throw Error()
            }

            if ( !added ){
                // Add it to the top level of the tree
                const ymap = newTreeNode( { id } )
                yArrayCollection.push( [ ymap ] )
            }

            resolve()
        })
    })
}


/** Create a ymap item from `id`
 *  @param {String} id - id of the noteDoc this node referes to.
 *  @return {YMap} - the new YMap object.
 */
function newTreeNode( { id } ){
    let ymap = new Y.Map()
    ymap.set( 'id', id )
    return ymap
}

function newChildTreeNode( { ymap, id } ){
    // create the new child map { id } node
    const ymapChild = newTreeNode( { id } )
    return pushChild( ymap, ymapChild )
}


function pushChild( ymap, ymapChild ){
    // if ymap already has children just push the new node onto it.
    if ( ymap.has( 'children' ) ){
        ymap.get( 'children' ).push( [ ymapChild ] )
    }else{
        // create a new child array node, push new { id } ymap onto it and add the new branch to `ymap`. YJS Observe Deep isn't handling this correctly afaic.
        const yarrayChildren = new Y.Array()
        ymap.set( 'children', yarrayChildren )
        yarrayChildren.push( [ ymapChild ] )
    }
    return ymapChild
}


function fnObserver( yEvents, transaction ){

    yEvents.forEach( yEvent => {
        const yName = this == yArrayCollection ? 'yArrayCollection' : 'yMapCollection';

        if ( yEvent.target instanceof Y.Map ){
            console.log( `fnObserver() ${yName} YMap - yEvent.keysChanged:`, yEvent.keysChanged, ', yEvent.changes:', yEvent.changes )
        }else
        if ( yEvent.target instanceof Y.Array ){
            console.log( `fnObserver() ${yName} YArray - yEvent.changes:`, yEvent.changes )
        }
    })
}


/****************
******/

async function go(  ){
    createYJSTYpes()

    const docToAdd1 = { id: 1 }
    await addItem( undefined, docToAdd1 )

    // add first child  - we don't see Observer yArrayCollection yArray yEvent ???
    const docToAdd2 = { id: 2 }
    await addItem( 0, docToAdd2 )

    // add second child
    const docToAdd3 = { id: 3 }
    await addItem( 0, docToAdd3 )
}

go()

When run this outputs:

fnObserver() yArrayCollection YArray - yEvent.changes: {
  added: Set(1) {
    Item {
      id: [ID],
      length: 1,
      origin: null,
      left: null,
      right: null,
      rightOrigin: null,
      parent: [YArray],
      parentSub: null,
      redone: null,
      content: [ContentType],
      info: 2
    }
  },
  deleted: Set(0) {},
  delta: [ { insert: [Array] } ],
  keys: Map(0) {}
}


==>> I expect to see yArrayCollection YArray - yEvent.changes here for  docToAdd2.

fnObserver() yArrayCollection YMap - yEvent.keysChanged: Set(1) { 'children' } , yEvent.changes: {
  added: Set(0) {},
  deleted: Set(0) {},
  delta: [],
  keys: Map(1) { 'children' => { action: 'add', oldValue: undefined } }
}
fnObserver() yArrayCollection YArray - yEvent.changes: {
  added: Set(1) {
    Item {
      id: [ID],
      length: 1,
      origin: [ID],
      left: [Item],
      right: null,
      rightOrigin: null,
      parent: [YArray],
      parentSub: null,
      redone: null,
      content: [ContentType],
      info: 2
    }
  },
  deleted: Set(0) {},
  delta: [ { retain: 1 }, { insert: [Array] } ],
  keys: Map(0) {}
}