How to use JavaScript Promise Chains Smartly?

How can you skip a step in a promise chain if a certain condition is met, without complicating the code?

function fetchData(shouldSkip) {
  fetch('https://api.example.com/step1')
    .then(response => response.json())
    .then(data => {
      if (shouldSkip(data)) {
        // Want to jump to final step. How?
      } else {
        return fetch('https://api.example.com/step2').then(response => response.json());
      }
    })
    .then(finalData => {
      // Need to work with finalData here, but what if there's no step2?
    });
}

How to use JavaScript Promise Chains Smartly?

How can you skip a step in a promise chain if a certain condition is met, without complicating the code?

function fetchData(shouldSkip) {
  fetch('https://api.example.com/step1')
    .then(response => response.json())
    .then(data => {
      if (shouldSkip(data)) {
        // Want to jump to final step. How?
      } else {
        return fetch('https://api.example.com/step2').then(response => response.json());
      }
    })
    .then(finalData => {
      // Need to work with finalData here, but what if there's no step2?
    });
}

Tizen AVPlay Player Can’t Play MP4 PLAYER_ERROR_CONNECTION_FAILED

I need to play a mp4 video and the source of video is on my cloud server. I try to play using video tag <video></video> it’s work correctly the video is playing. But when i try to using AVPlay API it’s throw the error PLAYER_ERROR_CONNECTION_FAILED when calling to prepare. This is my code

    webapis.avplay.open("https://preskripsi.com/assets/net.mp4");
    webapis.avplay.setDisplayRect(0, 0, 1920, 1080);
    webapis.avplay.setDisplayMethod(
      "PLAYER_DISPLAY_MODE_AUTO_ASPECT_RATIO"
    );
    webapis.avplay.setListener(listener);
    webapis.avplay.prepareAsync(function () {
      webapis.avplay.play();
    });

i’ve been put this on config.xml but it’s still not working

<access origin="*" subdomains="true"></access>
<tizen:privilege name="http://tizen.org/privilege/internet"/>
<tizen:privilege name="http://tizen.org/privilege/tv.window"/>

and i try to put this on config.xml

<tizen:privilege name="http://developer.samsung.com/privilege/avplay" />

but still not working

please help me, thanks.

Tizen AVPlay Player Can’t Play MP4 PLAYER_ERROR_CONNECTION_FAILED

I need to play a mp4 video and the source of video is on my cloud server. I try to play using video tag <video></video> it’s work correctly the video is playing. But when i try to using AVPlay API it’s throw the error PLAYER_ERROR_CONNECTION_FAILED when calling to prepare. This is my code

    webapis.avplay.open("https://preskripsi.com/assets/net.mp4");
    webapis.avplay.setDisplayRect(0, 0, 1920, 1080);
    webapis.avplay.setDisplayMethod(
      "PLAYER_DISPLAY_MODE_AUTO_ASPECT_RATIO"
    );
    webapis.avplay.setListener(listener);
    webapis.avplay.prepareAsync(function () {
      webapis.avplay.play();
    });

i’ve been put this on config.xml but it’s still not working

<access origin="*" subdomains="true"></access>
<tizen:privilege name="http://tizen.org/privilege/internet"/>
<tizen:privilege name="http://tizen.org/privilege/tv.window"/>

and i try to put this on config.xml

<tizen:privilege name="http://developer.samsung.com/privilege/avplay" />

but still not working

please help me, thanks.

Resize nodes bug

I have these sliders that will allow the shape to move over the canvas as well as change its width and height, but when I change the width or height of a shape its nodes that resize the shape increase in a different way then its should.

more over I am also looking for a way to do change in width and height in a way that the shapes area remain same, I was using boundBoxFunc for that but not able to pick the exact shape that I want.

I am trying to resize the rectangle using a input field such that when I change the width in input field it will change width of the rectangle.

function resizeRect(shape, layer, stage) {

  var anchors = [];
  anchors[rect1._id] = ['top-center', 'middle-right', 'middle-left', 'bottom-center'];


  const MIN_HEIGHT = height[0]
  const MAX_HEIGHT = height[1]
  const MIN_WIDTH = width[0]
  const MAX_WIDTH = width[1]

  const tr = new Konva.Transformer({
    nodes: [shape],
    ignoreStroke: true,
    padding: 5,
    boundBoxFunc: function(oldBoundBox, newBoundBox) {

      // Looking for a way to make this avaiable only for certain shapes (Like I have 4 shapes two rectangle and two group rectangle in l-shaped)
      if (oldBoundBox.width != newBoundBox.width && oldBoundBox.height == newBoundBox.height) {
        // console.log("change in width")
        // pick shape if its rect1 change width also when changing height so equal area
      } else {
        // console.log("change in height")
        // pick shape if its rect1 change height also when changing width so equal area

      }

      return newBoundBox;
    },
  });

  tr.rotateEnabled(false);

  tr.nodes([])

  stage.on('click tap', function(e) {


    if (e.target.getName() == '') {
      tr.nodes([]);
      return;
    }

    const keyPressed = e.evt.shiftKey || e.evt.ctrlKey;
    const isSelected = tr.nodes().indexOf(e.target) >= 0;

    tr.enabledAnchors(anchors[e.target._id]);

    if (!keyPressed && !isSelected) {
      tr.nodes([e.target]);
    } else if (keyPressed && isSelected) {
      const nodes = tr.nodes().slice();
      nodes.splice(nodes.indexOf(e.target), 1);
      tr.nodes(nodes);

    }
  });

  layer.add(tr);

}


var width = window.innerWidth;
var height = window.innerHeight;

var stage = new Konva.Stage({
  container: 'canvas',
  width: 512, // 4 CM = 128 PX/CM
  height: 896, // 7 CM = 128 PX/CM 
});

var layer = new Konva.Layer();


// Inner Items
rect1X = 210;
rect1Y = 300;
rect1Width = 31;
rect1Height = 190;
$('#coil_1_x').val(rect1X)
$('#coil_1_y').val(rect1Y)
$('#coil_1_width').val(rect1Width)
$('#coil_1_height').val(rect1Height)

var rect1 = new Konva.Rect({
  x: rect1X,
  y: rect1Y,
  width: rect1Width,
  height: rect1Height,
  name: 'rect1',
  fill: '#ec8e8e',
  stroke: '#ec8e8e',
  strokeWidth: 2,
  draggable: true
});

rect1.on('mouseover', function() {
  document.body.style.cursor = 'pointer';
});

rect1.on('mouseout', function() {
  document.body.style.cursor = 'default';
});

rect1.on('dragmove', function() {
  targetRect = rect1.getClientRect();
  $('#coil_1_x').val(targetRect.x)
  $('#coil_1_y').val(targetRect.y)
});

var oldRect1 = '';
rect1.on('transformstart', () => {
  oldRect1 = { ...rect1
  };
})

rect1.on('transform', function() {

  targetRect = rect1.getClientRect();
  rect1.setWidth(rect1.width() * rect1.scaleX());
  rect1.setHeight(rect1.height() * rect1.scaleY());
  $('#coil_1_width').val(Math.round(targetRect.width));
  $('#coil_1_height').val(targetRect.height);
  rect1.scaleX(1);
  rect1.scaleY(1);
});

$('#coil_1_x').keyup(function() {
  rect1.setX($(this).val());
});

$('#coil_1_y').keyup(function() {
  rect1.setY($(this).val());
});

$('#coil_1_width').keyup(function() {
  rect1.setWidth($(this).val());
  // if i do the changes in scaleX we got something like a really big width in thousands 
});

$('#coil_1_height').keyup(function() {
  rect1.setHeight($(this).val());
});


layer.add(rect1);

resizeRect(rect1, layer, stage);

stage.add(layer);
body {
  font-family: system-ui;
  background: black;
  color: white;
  text-align: center;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
  <link rel="stylesheet" href="css/style.css">
</head>

<body>
  <div id="main-container" class="container">
    <div class="row">
      <div class="col-md-1"></div>
      <div id="canvas" class="col-md-6"></div>
      <div id="slider" class="col-md-4">
        <div class="row">
          <div class="col-md-6">
            <h3>Slider</h3>
          </div>

        </div>


        <hr>
        <div class="row">
          <div class="form-group col-md-6">
            <label for="">Coil 1 X (Red)</label>
            <input type="number" class="form-control" id="coil_1_x">
          </div>

          <div class="form-group col-md-6">
            <label for="">Coil 1 Y</label>
            <input type="number" class="form-control" id="coil_1_y">
          </div>

          <div class="form-group col-md-6">
            <label for="">Coil 1 Width</label>
            <input type="number" class="form-control" id="coil_1_width">
          </div>

          <div class="form-group col-md-6">
            <label for="">Coil 1 Height</label>
            <input type="number" class="form-control" id="coil_1_height">
          </div>


        </div>
      </div>
      <div class="col-md-1"></div>
    </div>
  </div>
  <script src="https://unpkg.com/konva@9/konva.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>

</html>

I need to chunk an array into smaller arrays of a specified size and I’m unsure about the most efficient approach.”

Approach 1

function chunk(arr, size) {
    const chunkedArr = [];
    let i = 0;
    while(i < arr.length) {
        chunkedArr.push(arr.splice(0, size))
    }
    return chunkedArr;
};

Approach 2

function chunkArray(arr, size) {
    // Check if the array is empty or if size is not positive
    if (arr.length === 0 || size <= 0) {
        return [];
    }

    // Calculate the number of chunks needed
    const numChunks = Math.ceil(arr.length / size);

    // Create an array to store the chunked arrays
    const chunkedArray = [];

    // Loop through the array and push chunks into the chunkedArray
    for (let i = 0; i < numChunks; i++) {
        const start = i * size;
        const end = start + size;
        chunkedArray.push(arr.slice(start, end));
    }

    return chunkedArray;
}

Given the above approaches, both achieve the desired outcome right. I’m confused if approach 1 is more preferrable than approach 2. Is it even necessary in approach 2 to check for the size and emptyness of an array. Help me what’s the right way of approaching this problem.

send audio blobs, receive python websocket streamer invalid input error

Send audio blobs from client every 4seconds with websocket. Here my eventListerner sending :

recorder.mediaRecorder.addEventListener(
              "dataavailable",
              async (event) => {
                recorder.audioBlobs.push(event.data);

                const blob = new Blob(recorder.audioBlobs, {
                  type: "audio/wav; codecs=MS_PCM",
                });

                if (recorder.socket?.readyState === 1) {
                  recorder.socket.send(blob);
                }
              }
              );
              
              recorder.mediaRecorder.start(DELAY_TIME_MILLISECONDS);

            recorder.setStatus();

            recorder.visualize(stream);
          }

python receive from websocket.receive_bytes():

while True:
                bytes_data = await websocket.receive_bytes()
                print("============received audio bytes")
                if bytes_data:
                    audio_bytes = BytesIO(bytes_data)
                    streamer = StreamReader(audio_bytes)
                    streamer.add_basic_audio_stream(frames_per_chunk=chunk_size, sample_rate=sample_rate, format='fltp')
                    stream_iterator = torch.concat([stream_arr[0] for stream_arr in streamer.stream()])
                    array = torch.Tensor.numpy(stream_iterator)
                    array = array[:, 0]

                    chunk_reader = AudioChunkIterator(samples=array, chunk_len_in_secs=chunk_len_in_secs, sample_rate=sample_rate)

                    sampbuffer = np.zeros([buffer_len], dtype=np.float32)
                    buffer_list = []
                    result = ''
                    text = ''
                    for i, chunk in enumerate(chunk_reader):
                        sampbuffer[:-chunk_size] = sampbuffer[chunk_size:]
                        sampbuffer[-chunk_size:] = chunk
                        buffer_list.append(np.array(sampbuffer))

Here all works normal if append every chunk to prevs. But Blob size became big and real-time behind shedule, I want to send only this chunk per 4seconds. if send it like below:

...
        async (event) => {
                const blob = new Blob([event.data], {
                  type: "audio/wav; codecs=MS_PCM",
                });

                if (recorder.socket?.readyState === 1) {
                  recorder.socket.send(blob);
                }
              }

it receives first blob, but at the second blob

error at the server side like below:
enter image description here

enter image description here

want send only last chunk from clint

How to call an instance method whose name is in a string?

I want to call the instance methods whose name is passed with the func input element but my code fails because it can’t find the TestClass instance methods in the global window. How can I achieve this?

class TestClass {
  func = document.getElementById('func');

  result = document.getElementById('result');

  func1 = () => {
    this.result.innerHTML = 'func1 called';
  };

  func2() {
    this.result.innerHTML = 'func2 called';
  }

  funcListener = () => {
    window[this.func.value]();
  };

  constructor() {
    this.func.addEventListener('change', this.funcListener);
  }
}

new TestClass();
functest.html

<!doctype html>
<html lang="en-US">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>functest</title>
</head>

<body>
  <input id="func" placeholder="enter function to call: func1, func2" type="text" maxlength="200">
  <label id="result" for="func">result</label>
</body>

Property ‘add’ does not exist on type ‘FontFaceSet’

I’m following the Adding a font to a document or worker from the developer mozilla website.

This is the code they’re sharing

// Define a FontFace
const font = new FontFace("myfont", "url(myfont.woff)", {
  style: "italic",
  weight: "400",
  stretch: "condensed",
});

// Add to the document.fonts (FontFaceSet)
document.fonts.add(font);

But when I do exactly that, in my Angular app, I receive the following error

Property ‘add’ does not exist on type ‘FontFaceSet’.

Does somebody found a solution to it ?

Error deleting text in QuillJS editor with Vue.js 3 : Uncaught TypeError: Cannot read properties of null (reading ‘offset’)

I initialized the QuillJS editor on a Vue.js 3 project (option API), and here’s the code present in the component:

<script>
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import Quill from 'quill'

export default {
  name: 'AppChatContainer',
  components: { FontAwesomeIcon },
  props: {
    messages: {
      type: Array,
      required: true,
      default: () => []
    },
    isSending: {
      type: Boolean,
      default: false
    }
  },

  emits: ['new-message'],

  data() {
    return {
      quill: null
    }
  },

  mounted() {
    this.quill = new Quill('#message', {
      theme: 'bubble',
      modules: {
        toolbar: [
          ['bold', 'italic', { color: [] }],
          [{ list: 'ordered' }, { list: 'bullet' }]
        ]
      }
    })
  },

  methods: {
    handleSubmission() {
      const message = this.quill.getContents()
      this.$emit('new-message', message)
      // this.quill.setContents([{ insert: 'n' }]) // <= Error here
      // this.quill.setText('') // <= Error here
      this.quill.deleteText(0, this.quill.getLength()) // <= Error here
    },

    convertDeltaToHtml(delta) {
      const tempQuill = new Quill(document.createElement('div'))
      tempQuill.setContents(delta)
      return tempQuill.root.innerHTML
    }
  }
}
</script>

<template>
  <form class="h-100 position-relative" @submit.prevent="handleSubmission">
    <div class="flex-grow-1 overflow-y-scroll">
      <div
        v-for="message in messages"
        :key="message.id"
        :class="`message mb-4 ${message.isAuthor ? 'author' : ''} ${message.isSending ? 'sending' : ''}`"
      >
        <div class="content" v-html="convertDeltaToHtml(message.content)" />
        <small v-if="message.isSending" class="text-gray-700 fw-light d-block mt-1 ms-2 me-3">
          Envois en cours...
        </small>
        <small v-else class="text-gray-700 fw-light d-block mt-1 ms-2 me-3">
          {{ message.isAuthor ? 'Vous' : message.authorName }}, le {{ message.date }}</small
        >
      </div>
    </div>
    <div class="message-container">
      <div id="message" />
      <button type="submit" class="btn btn-amsom-green" :disabled="isSending">
        <font-awesome-icon v-if="!isSending" icon="paper-plane" />
        <div v-else class="spinner-border spinner-border-sm" role="status">
          <span class="visually-hidden">Envois en cours...</span>
        </div>
      </button>
    </div>
  </form>
</template>

<style scoped>
// ...
</style>

When I submit the form, handleSubmission() method is called. When I try to delete the editor content I have this error :

Uncaught TypeError: Cannot read properties of null (reading 'offset')
    at quill.js?v=b3144345:12600:26
    at Array.map (<anonymous>)
    at Proxy.normalizedToRange (quill.js?v=b3144345:12597:31)
    at Proxy.getRange (quill.js?v=b3144345:12586:25)
    at Proxy.update (quill.js?v=b3144345:12723:43)
    at Proxy.update (quill.js?v=b3144345:13796:20)
    at Proxy.getSelection (quill.js?v=b3144345:13690:10)
    at Proxy.modify (quill.js?v=b3144345:13906:44)
    at Proxy.deleteText (quill.js?v=b3144345:13553:19)
    at Proxy.handleSubmission (AppChatContainer.vue:47:18)

I’ve tried several ways of deleting content from the editor, but I always have the same problem…

handleSubmission() {
      const message = this.quill.getContents()
      this.$emit('new-message', message)
      // this.quill.setContents([{ insert: 'n' }])
      // this.quill.setText('');
      this.quill.deleteText(0, this.quill.getLength())
    },

How to Initialize a NetSuite Sandbox Environment?

Recently, our company purchased a new sandbox environment with the intention of facilitating developer learning and testing. However, during the setup, the administrator accidentally imported production data into this sandbox environment. Now, we are seeking a way to initialize or reset this sandbox environment to its default state, essentially making it a clean slate for development purposes.

I have explored various options but haven’t found a straightforward solution to address this issue. Specifically, I am interested in knowing if NetSuite Sandbox offers any functionality to initialize or reset the sandbox environment to its default settings, effectively removing any imported data and configurations.

Any insights, recommendations, or guidance on how to achieve this goal would be greatly appreciated. Thank you!

Develop Add-in from an existing spreadsheet Excel JavaScript API

How do you develop an Add-in using Excel JavaScript API from an existing spreadsheet? Whenever I run npm start, a blank workbook is created. Manifest.xml seems to be the appropriate place, since npm start executes office-addin-debugging start manifest.xml, but not sure what to change. Don’t need a visual studio solution.

This seems like a basic question, but I haven’t found anything in the api documentation or tutorials on learn.microsoft.com. Links to point me in the right direction are welcomed.

For context, I’m developing an add-in for a payroll workbook that will pull data from specific cells and reformat it in a new workbook. So I need to be able to develop the add-in within the workbook I’ve already created.

Here is my manifest.xml file:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="TaskPaneApp">
  <Id>3b1c4cad-3081-4941-9176-4ba875ffa3b5</Id>
  <Version>1.0.0.0</Version>
  <ProviderName>Contoso</ProviderName>
  <DefaultLocale>en-US</DefaultLocale>
  <DisplayName DefaultValue="Convert"/>
  <Description DefaultValue="A template to get started."/>
  <IconUrl DefaultValue="https://localhost:3000/assets/icon-32.png"/>
  <HighResolutionIconUrl DefaultValue="https://localhost:3000/assets/icon-64.png"/>
  <SupportUrl DefaultValue="https://www.contoso.com/help"/>
  <AppDomains>
    <AppDomain>https://www.contoso.com</AppDomain>
  </AppDomains>
  <Hosts>
    <Host Name="Workbook"/>
  </Hosts>
  <DefaultSettings>
    <SourceLocation DefaultValue="https://localhost:3000/taskpane.html"/>
  </DefaultSettings>
  <Permissions>ReadWriteDocument</Permissions>
  <VersionOverrides xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="VersionOverridesV1_0">
    <Hosts>
      <Host xsi:type="Workbook">
        <DesktopFormFactor>
          <GetStarted>
            <Title resid="GetStarted.Title"/>
            <Description resid="GetStarted.Description"/>
            <LearnMoreUrl resid="GetStarted.LearnMoreUrl"/>
          </GetStarted>
          <FunctionFile resid="Commands.Url"/>
          <ExtensionPoint xsi:type="PrimaryCommandSurface">
            <OfficeTab id="TabHome">
              <Group id="CommandsGroup">
                <Label resid="CommandsGroup.Label"/>
                <Icon>
                  <bt:Image size="16" resid="Icon.16x16"/>
                  <bt:Image size="32" resid="Icon.32x32"/>
                  <bt:Image size="80" resid="Icon.80x80"/>
                </Icon>
                <Control xsi:type="Button" id="TaskpaneButton">
                  <Label resid="TaskpaneButton.Label"/>
                  <Supertip>
                    <Title resid="TaskpaneButton.Label"/>
                    <Description resid="TaskpaneButton.Tooltip"/>
                  </Supertip>
                  <Icon>
                    <bt:Image size="16" resid="Icon.16x16"/>
                    <bt:Image size="32" resid="Icon.32x32"/>
                    <bt:Image size="80" resid="Icon.80x80"/>
                  </Icon>
                  <Action xsi:type="ShowTaskpane">
                    <TaskpaneId>ButtonId1</TaskpaneId>
                    <SourceLocation resid="Taskpane.Url"/>
                  </Action>
                </Control>
                <Control xsi:type="Button" id="ToggleProtection">
                  <Label resid="ProtectionButtonLabel" />
                  <Supertip>
                      <Title resid="ProtectionButtonLabel" />
                      <Description resid="ProtectionButtonToolTip" />
                  </Supertip>
                  <Icon>
                      <bt:Image size="16" resid="Icon.16x16"/>
                      <bt:Image size="32" resid="Icon.32x32"/>
                      <bt:Image size="80" resid="Icon.80x80"/>
                  </Icon>
                  <Action xsi:type="ExecuteFunction">
                     <FunctionName>toggleProtection</FunctionName>
                  </Action>
                </Control>
              </Group>
            </OfficeTab>
          </ExtensionPoint>
        </DesktopFormFactor>
      </Host>
    </Hosts>
    <Resources>
      <bt:Images>
        <bt:Image id="Icon.16x16" DefaultValue="https://localhost:3000/assets/icon-16.png"/>
        <bt:Image id="Icon.32x32" DefaultValue="https://localhost:3000/assets/icon-32.png"/>
        <bt:Image id="Icon.80x80" DefaultValue="https://localhost:3000/assets/icon-80.png"/>
      </bt:Images>
      <bt:Urls>
        <bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/>
        <bt:Url id="Commands.Url" DefaultValue="https://localhost:3000/commands.html"/>
        <bt:Url id="Taskpane.Url" DefaultValue="https://localhost:3000/taskpane.html"/>
      </bt:Urls>
      <bt:ShortStrings>
        <bt:String id="GetStarted.Title" DefaultValue="Get started with your sample add-in!"/>
        <bt:String id="CommandsGroup.Label" DefaultValue="Commands Group"/>
        <bt:String id="TaskpaneButton.Label" DefaultValue="Show Taskpane"/>
        <bt:String id="ProtectionButtonLabel" DefaultValue="Toggle Worksheet Protection" />
      </bt:ShortStrings>
      <bt:LongStrings>
        <bt:String id="GetStarted.Description" DefaultValue="Your sample add-in loaded succesfully. Go to the HOME tab and click the 'Show Taskpane' button to get started."/>
        <bt:String id="TaskpaneButton.Tooltip" DefaultValue="Click to Show a Taskpane"/>
        <bt:String id="ProtectionButtonToolTip" DefaultValue="Click to protect or unprotect the current worksheet." />
      </bt:LongStrings>
    </Resources>
  </VersionOverrides>
</OfficeApp>

Why do certain emails go missing when attempting to fetch them using IMAP?

import Imap from 'node-imap'
import { simpleParser } from 'mailparser'
import { inspect } from 'util'

export default async function handler(req, res) {
  try {
    const cred = req.body

    const imap = new Imap({
      user: cred.user,
      password: cred.password,
      host: cred.host,
      port: 993,
      tls: true
    })

    imap.on('ready', async function () {
      try {
        const messages = await fetchMessages(imap)
        res.status(200).json(messages)
      } catch (error) {
        console.error('Error fetching messages:', error)
        res.status(500).json({ error: 'An error occurred while fetching messages' })
      } finally {
        imap.end()
      }
    })

    imap.on('error', function (err) {
      console.error('IMAP Error:', err)
      res.status(500).json({ error: 'An error occurred while connecting to the mail server' })
    })

    imap.on('end', function () {
      console.log('Connection ended')
    })

    imap.connect()
  } catch (error) {
    console.error('Error:', error)
    res.status(500).json({ error: 'An unexpected error occurred' })
  }
}

async function fetchMessages(imap) {
  return new Promise((resolve, reject) => {
    imap.openBox('INBOX', true, (err, box) => {
      if (err) {
        reject(err)

        return
      }

      const messages = []

      const f = imap.seq.fetch('1:*', {
        bodies: '',
        struct: true
      })

      f.on('message', async function (msg, seqno) {
        const messageData = {}

        msg.on('body', async function (stream, info) {
          try {
            const buffer = await parseMessage(stream)
            const parsed = await simpleParser(buffer)
            messages.push(parsed)
          } catch (error) {
            console.error('Error parsing message:', error)
          }
        })

        msg.on('attributes', function (attrs) {
          console.log('Attributes:', inspect(attrs, false, 8))
        })

        msg.on('end', function () {
          // console.log('Finished');
        })
      })

      f.on('error', function (err) {
        console.error('Fetch error:', err)
        reject(err)
      })

      f.on('end', function () {
        console.log('Done fetching all messages!')
        resolve(messages)
      })
    })
  })
}

Why are emails sometimes missing when making API requests for IMAP integration with Next.js?
I attempted to use async/await methods, but they did not function effectively.
This is my code where I’m attempting to retrieve all emails including headers and bodies.
I’m missing more emails in production than localhost.
The version of node-imap I’m using is “^0.9.6”, and my Next.js version is “13.2.4”

TypeError: Joi.string(…).custome is not a function

I want to add custom validation but I got error while I add custom function please give me solution

 module.exports.placeOrder = Joi.object({
  buyer: Joi.object({
    id: Joi.string().guid().required(),
    name: Joi.string().required(),
    email: Joi.string().email().required(),
  }).required(),
  organisation: Joi.object({
    id: Joi.string().required(),
    title: Joi.string().required(),
  }).required(),
  updated_by: Joi.object({
    id: Joi.string().guid().required(),
    name: Joi.string().allow(null),
    email: Joi.string().allow(null),
  }).required(),
  program: Joi.array()
    .items(
      Joi.object({
        id: Joi.string()
          .regex(/^[a-zA-Z0-9-_]+={0,2}$/)
          .required(),
        producer: Joi.object({
          id: Joi.string().guid().required(),
          name: Joi.string().custome(isValidInput).required().allow(null),
          email: Joi.string().email().allow(null),
        }).required(),
        channel_partner: Joi.object({
          id: Joi.string().guid().required(),
          name: Joi.string().required(),
          email: Joi.string().required(),
        }).required(),
        igpid: Joi.string()
          .regex(/^[a-zA-Z0-9-_]+={0,2}$/)
          .optional(),
        title: Joi.string().required(),
        description: Joi.string().optional(),
        initial_units: Joi.number().integer().required(),
        program_source: Joi.string().required(),
        genome_insight: Joi.string().optional(),
        reach: Joi.number().integer().required(),
        available_units: Joi.number().integer().optional(),
        status: Joi.string().required(),
        sdg: Joi.object({
          program_sdg_names: Joi.array().items(Joi.string()).required(),
          program_sdg_targets: Joi.array().items(Joi.string()).required(),
        }).optional(),
       })
      )
      .required(),
   });

I want to add custom validation for that no external HTML tags or script is injected. I want to make sure that no malicious scrip could be injected in the request