Recursive function returns correctly and array of objects but the function which calls it receives undefined [duplicate]

I would like to ask for some help. I have to work with a recursive function in order to traverse a tree in DFS manner. The algorithm works fine, despite the function still in development so please have mercy on me with that in mind.
I, however, need to use axios in my recursion because under some condition I must pull my data from the database, therefore my recursive function becomes async + it has a for loop.
Here is the code. A small walk-through:

  • traverse traverses the tree in DFS manner and calls my API under some condition
  • trversewrapper calls the function in a for loop
  • getMaxCia values calls the api for the values

Why is the result array in the traversWrapper equal to [null] and therefore undefined instead of returning my array of objects? I console log the return of the recursive function an it indeed returns an array of valid objects.

async traverse(
    assetDto: NestedAssetDto,
    direction: string,
    startNodeChildren: NestedAssetDto[],
    useOverwritten: boolean,
    accountId: string,
    traversedTree: NestedAssetDto[] = [],
    alreadyTraversed: NestedAssetDto[] = [],
    ): Promise<NestedAssetDto[]>{
      if(!assetDto && !isObject(assetDto)){
      console.log('Asset is undefined or is not an object')
      return [];
      }

      if(!startNodeChildren ||  startNodeChildren.length === 0 && assetDto.identifier === traversedTree[0].identifier){
        console.log(`Traversed array in the traverse function: ${JSON.stringify(traversedTree)}`)
        console.log("This is the end of the recursive function. Goodbye.")
        return traversedTree;
      }

      const startNodePushed = traversedTree.find(asset => asset.identifier === traversedTree[1].identifier);
      if(!startNodePushed){
        traversedTree.push(assetDto)
        alreadyTraversed.push(assetDto);
      };

      const visitedAsset = traversedTree.find(asset => asset.identifier === assetDto.identifier);
      !visitedAsset && traversedTree.push(assetDto);
      alreadyTraversed.push(assetDto);

      if(traversedTree && traversedTree.length > 1 && traversedTree[0].identifier === assetDto.identifier){
        console.log("We are back at the starting node for a next iteration")
        assetDto.hasNestedAsset = startNodeChildren;
      }
      
      console.log(`Direction: ${direction} for ${assetDto.identifier}. Should use overwritten ${useOverwritten}`);
      let confidentialityFromDb;
      let integrityFromDb;
      let availabilityFromDb;

      if(useOverwritten && traversedTree[0].identifier === assetDto.identifier){
        if(!assetDto.props.overwrittenConfidentiality || !assetDto.props.overwrittenIntegrity || !assetDto.props.overwrittenAvailability){
          console.log('Asset overwritten flags are true but overwritten props are undefined. Returning the tree as it is now')
          return traversedTree;
        }
      }

      if(assetDto.assetType !== AssetType.BusinessProcess && direction === Direction.Top){
        console.log('Asset is not of type BP but direction is up. By law, this can not be true.')
        return [];
      }

      if(!assetDto.hasNestedAsset || assetDto.hasNestedAsset.length === 0){
        const isFirstElement = traversedTree && traversedTree.length === 0;
        console.log( `Asset ${JSON.stringify(assetDto)} does not have nested assets. This is the ${isFirstElement ? 'first and only' : 'last'} element in the tree.`);
        console.log(`Starting again with ${traversedTree[0].identifier}`)
        return this.traverse(traversedTree[0], direction, startNodeChildren, useOverwritten, accountId, traversedTree, alreadyTraversed);
      }

      const filteredNestedAssets = assetDto.hasNestedAsset.reduce((acc, nestedAsset) => {
        if ( (assetDto.assetType === AssetType.BusinessProcess && nestedAsset.assetType === AssetType.BusinessProcess && direction === Direction.Top) || (assetDto.assetType === AssetType.BusinessProcess && nestedAsset.assetType !== AssetType.BusinessProcess && direction === Direction.Bottom)
          || (assetDto.assetType !== AssetType.BusinessProcess && nestedAsset.assetType !== AssetType.BusinessProcess && direction === Direction.Bottom)
        ) { acc.push(nestedAsset) }
        return acc;
      }, []);

      const nodeConfidentiality = useOverwritten ? assetDto.props.overwrittenConfidentiality : assetDto.props.calculatedConfidentiality;
      const nodeIntegrity = useOverwritten ? assetDto.props.overwrittenIntegrity : assetDto.props.calculatedIntegrity;
      const nodeAvailability = useOverwritten ? assetDto.props.overwrittenAvailability :  assetDto.props.calculatedAvailability;

      for(let [index, element] of filteredNestedAssets.entries()){
        {
          if(assetDto.identifier === traversedTree[0].identifier){
            startNodeChildren.splice(index, 1);
          }

          if(element.calculateUsingOverwrittenValues && element.overwriteValues){
            if(!element.props.overwrittenConfidentiality || !element.props.overwrittenAvailability || !element.props.overwrittenIntegrity){
              return
            }
          }

          const nestedNodeConfidentiality = useOverwritten ? element.props.overwrittenConfidentiality : element.props.calculatedConfidentiality
          const nestedNodeIntegrity = useOverwritten ? element.props.overwrittenIntegrity : element.props.calculatedIntegrity
          const nestedNodeAvailability = useOverwritten ? element.props.overwrittenAvailability :  element.props.calculatedAvailability
          
          if(nestedNodeConfidentiality > nodeConfidentiality || nestedNodeIntegrity > nodeIntegrity || nestedNodeAvailability > nodeAvailability){
            if(useOverwritten){
             {
                const ciaFromDb = await this.getCiaMaxValues(accountId, element.identifier, direction)
                console.log(`Values from db: ${JSON.stringify(ciaFromDb)}`)
                confidentialityFromDb = ciaFromDb.maxConfidentiality;
                integrityFromDb = ciaFromDb.maxIntergrity;
                availabilityFromDb = ciaFromDb.maxAvailability;
              }         
            } else{
              {
                const ciaFromDb = await this.getCiaMaxValues(accountId, element.identifier, direction)
                console.log(`Values from db: ${JSON.stringify(ciaFromDb)}`)
                confidentialityFromDb = ciaFromDb.maxConfidentiality;
                integrityFromDb = ciaFromDb.maxIntergrity;
                availabilityFromDb = ciaFromDb.maxAvailability;
              }         
            }
          }
          let alreadyCalculatedAsset = traversedTree.find(asset => asset.identifier === element.identifier);

          if(alreadyCalculatedAsset){
            console.log(`This asset is an already visted asset: ${JSON.stringify(alreadyCalculatedAsset)}`)

            const visitedAssetConfidentiality = useOverwritten ? alreadyCalculatedAsset.props.overwrittenConfidentiality 
            : alreadyCalculatedAsset.props.calculatedConfidentiality;
            const visitedAssetIntergrity  = useOverwritten ? alreadyCalculatedAsset.props.overwrittenIntegrity 
            : alreadyCalculatedAsset.props.calculatedIntegrity;
            const visitedAssetAvailability  = useOverwritten ? alreadyCalculatedAsset.props.overwrittenAvailability 
            : alreadyCalculatedAsset.props.calculatedAvailability;
            const { value: maxConfidentiality } = confidentialityFromDb ? confidentialityFromDb : calculateCIAMaxValue(visitedAssetConfidentiality, nodeConfidentiality);
            const { value: maxIntergrity } =  integrityFromDb ? integrityFromDb : calculateCIAMaxValue(visitedAssetIntergrity, nodeIntegrity);
            const { value: maxAvailability } = availabilityFromDb ? availabilityFromDb : calculateCIAMaxValue(visitedAssetAvailability, nodeAvailability);

            alreadyCalculatedAsset = {
              ...alreadyCalculatedAsset,
              props: 
              {
                [useOverwritten ? 'overwrittenConfidentiality' : 'calculatedConfidentiality']: maxConfidentiality, 
                [useOverwritten ? 'overwrittenIntegrity' : 'calculatedIntegrity']: maxIntergrity,
                [useOverwritten ? 'overwrittenAvailability' : 'calculatedAvailability']: maxAvailability,
                overwriteValues: useOverwritten ? true : false,
                calculatedUsingOverwrittenValues: useOverwritten ? true : false
              },
              oldProps: 
              {
                [useOverwritten ? 'overwrittenConfidentiality' : 'calculatedConfidentiality']: nestedNodeConfidentiality, 
                [useOverwritten ? 'overwrittenIntegrity' : 'calculatedIntegrity']: nestedNodeIntegrity,
                [useOverwritten ? 'overwrittenAvailability' : 'calculatedAvailability']: nestedNodeAvailability,
              }
            };

            
            console.log(`The asset is visited again. Here is the result after the mutate: ${alreadyCalculatedAsset}`)
            this.traverse(element, direction, startNodeChildren, useOverwritten, accountId, traversedTree);
          }

          const { value: maxConfidentiality } = confidentialityFromDb ? confidentialityFromDb : calculateCIAMaxValue(nestedNodeConfidentiality, nodeConfidentiality);
          const { value: maxIntergrity } =  integrityFromDb ? integrityFromDb : calculateCIAMaxValue(nestedNodeIntegrity, nodeIntegrity);
          const { value: maxAvailability } = availabilityFromDb ? availabilityFromDb : calculateCIAMaxValue(nestedNodeAvailability, nodeAvailability);

          element = {
            ...element,
            props: 
            {
              [useOverwritten ? 'overwrittenConfidentiality' : 'calculatedConfidentiality']: maxConfidentiality, 
              [useOverwritten ? 'overwrittenIntegrity' : 'calculatedIntegrity']: maxIntergrity,
              [useOverwritten ? 'overwrittenAvailability' : 'calculatedAvailability']: maxAvailability,
              overwriteValues: useOverwritten ? true : false,
              calculatedUsingOverwrittenValues: useOverwritten ? true : false
            },
            oldProps: 
              {
                [useOverwritten ? 'overwrittenConfidentiality' : 'calculatedConfidentiality']: nestedNodeConfidentiality, 
                [useOverwritten ? 'overwrittenIntegrity' : 'calculatedIntegrity']: nestedNodeIntegrity,
                [useOverwritten ? 'overwrittenAvailability' : 'calculatedAvailability']: nestedNodeAvailability,
              }
          }

          //For debbuging at any time
          console.log(`current node id: ${element.identifier}, parent node id: ${assetDto.identifier},`)
          console.log(`current node c: ${nestedNodeConfidentiality}, parent node c: ${nodeConfidentiality}, max c: ${maxConfidentiality}`)
          console.log(`current node i: ${nestedNodeIntegrity}, parent node i: ${nodeIntegrity}, max i: ${maxIntergrity}`)
          console.log(`current node a: ${nestedNodeAvailability}, parent node a: ${nodeAvailability}, max a: ${maxAvailability}`)
                 
          traversedTree.push(element);
          this.traverse(element, direction, startNodeChildren, useOverwritten, accountId, element.oldProps, traversedTree);
        }
      };
  }

  async getAssetTreePath(accountId: string, assetId: string) {
    const url = `${process.env.BASE_URL}/accounts/${accountId}/assets/${assetId}/assetsTree`;
    const secretKey = process.env.LAMBDA_SECRET_KEY;
    const secretBase64Hash = generateSecretBase64Hash(secretKey, url)
    const config = {
      headers: {
        'x-lambda-hash': secretBase64Hash,
      }
    }
    const { data } = await axios.get(url, config);
    return data;
  }

  async traverseWrapper(nestedAssetArray: NestedAssetDto[], accountId: string) {
    if (nestedAssetArray.length > 2) {
      const errMessage =
        "Received an array which includes more than two elements. Cannot proceed in more than 2 directions.";
      console.log(errMessage);
      throw new Error(errMessage);
    }

    const result: NestedAssetDto[][]=[]
    for(const el of nestedAssetArray){
      const useOverwritten = el.overwriteValues && el.calculateUsingOverwrittenValues;
      const arrayOfTraversedEl = el ? await this.traverse(el, el.direction, el.hasNestedAsset, useOverwritten, accountId) : [];
      console.log(`result ${JSON.stringify(arrayOfTraversedEl)}`)

      result.push(arrayOfTraversedEl);
    }
    console.log(`result ${JSON.stringify(result)}`)
    if(result.length === 2){
      return result[0].concat(result[1])
    }else if(result.length === 1){
      return result[0]
    }
    return [];

  }
  async updateCiaInDb(accountId: string, assetId: string, ciaToUpdate?: AssetDto[]) {
    console.log(`C I A flattened array with elements to update: ${JSON.stringify(ciaToUpdate)}`)

    if(!ciaToUpdate || ciaToUpdate.length === 0){
      console.log("Array of elements to update is empty, therefore will not send a request.")
      return;
    }
    const url = `${process.env.BASE_URL}/accounts/${accountId}/assets/${assetId}/updateCia`;
    const secretKey = process.env.LAMBDA_SECRET_KEY;
    const secretBase64Hash = generateSecretBase64Hash(secretKey, url)
    const config = {
      headers: {
        'x-lambda-hash': secretBase64Hash,
      },
    }
    await axios.put(url, ciaToUpdate, config);
  }

  getCiaMaxValues = async (accountId: string, assetId: string, direction: String) => {
    const secretKey = process.env.LAMBDA_SECRET_KEY;
    const url = `${process.env.BASE_URL}/accounts/${accountId}/assets/${assetId}/nestedAssetsMaxValues?useOverwritten=${direction}`
    const secretBase64Hash = generateSecretBase64Hash(secretKey, url)
    const config = {
      headers: {
        'x-lambda-hash': secretBase64Hash,
      }
    }
    const response = await axios.get(url, config)
    const { data } = response;
    return data
  }