#natschz_code

1 messages ยท Page 1 of 1 (latest)

craggy troutBOT
#

๐Ÿ‘‹ Welcome to your new thread!

โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

๐Ÿ”— This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1230156730143604798

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

elfin lionBOT
south frost
#

Are you turning the reader off after you've connected to it?

quaint oasis
#

Yes exactly

south frost
#

ah you have it set to onUnexpectedReaderDisconnect: () => { }

#

which is why you're not seeing the callback

quaint oasis
#

This is the exception that i get

#

So I've set the callback (just reduced the sample because only 480 charakters are allowed) :

onUnexpectedReaderDisconnect: () => {
  console.log("Currently: unexpectedDisconnect")
}

And I'm getting the console output, but it still throws the Unhandled promise rejection Error: Could not communicate with the Reader. error.

south frost
#

I mean you shouldn't try to run any other actions except for reconnection flow once you receive onUnexpectedReaderDisconnect

elfin lionBOT
quaint oasis
#

So currently, I'm not even trying to reconnect:

const terminal = StripeTerminal.create({
  onFetchConnectionToken: fetchConnectionToken(),
  onUnexpectedReaderDisconnect: () => {
    console.log("Disconnected")
  },
  onConnectionStatusChange: (data) => {
    console.log("onConnectionStatusChange", {data})
  },
});


terminal.discoverReaders().then(discoverResult => {
  const reader = discoverResult.discoveredReaders.find(reader => reader.serial_number === "SERIAL_NUMBER")

  terminal.connectReader(reader).then(connectResult => {
    console.log("Connected to reader", connectResult)
  }).catch(error => {
    console.error("Error connecting to reader", error)
  })
}).catch(error => {
  console.error("Error discovering readers", error)
})

This is all I'm doing right now. Then turning the reader off, will result in the exception shown above.

south frost
#

Sorry, I feel like I am missing something. Can you clarify exactly when you see the promise rejection error?

#

also onFetchConnectionToken: fetchConnectionToken() feels wrong

You're invoking the function fetchConnectionToken yourself there.

#

Ideally, you should only pass function definition, the SDK invokes it on its own

quaint oasis
#

Yea sorry this are two nested functions where I pass the URL to the outer one and then the other es returned but this works fine

#

So just for clarification, I'm executing the code above, then the terminal connects and everything works fine.

Then I'm turning the terminal off, it then takes ~2min until I get the error (without doing anything else)

#

This is the full console output

#

Besides that, I noticed calling getConnectionStatus in the meantime, before the error happens, will also always return connected, even though the terminal is powered off.

south frost
#

Besides that, I noticed calling getConnectionStatus in the meantime, before the error happens, will also always return connected, even though the terminal is powered off
That's expected due to how the SDK has been designed today. The status of the reader is updated when the SDK makes a request for something

quaint oasis
south frost
#

A workaround there is to use a non user-facing function like: https://docs.stripe.com/terminal/references/api/js-sdk#clear-reader-display which returns a promise that throws an error if the reader isn't connected.

So just to clarify, you're seeing promise rejected error automatically after the reader is disconnected? Are you sure no other function is running that triggers this error?

#

Can you share your complete code?

quaint oasis
#

Sure

#
-content_for :javascript do
  %script{src: "https://js.stripe.com/terminal/v1/"}


-content_for :javascript do
  :javascript
    function fetchConnectionToken(connectionTokenUrl) {
      console.log("Currently: fetchConnectionToken")
      return () => {
        // Do not cache or hardcode the ConnectionToken. The SDK manages the ConnectionToken's lifecycle.
        return fetch(connectionTokenUrl, {method: "POST"})
          .then(function (response) {
            return response.json();
          })
          .then(function (data) {
            return data.token;
          });
      }
    }

    const terminal = StripeTerminal.create({
      onFetchConnectionToken: fetchConnectionToken("INTERNAL_URL"),
      onUnexpectedReaderDisconnect: () => {
        console.log("Disconnected")
      },
      onConnectionStatusChange: (data) => {
        console.log("onConnectionStatusChange", {data})
      },
    });


    terminal.discoverReaders().then(discoverResult => {
      const reader = discoverResult.discoveredReaders.find(reader => reader.serial_number === "SERIAL_NUMBER")

      terminal.connectReader(reader).then(connectResult => {
        console.log("Connected to reader", connectResult)
      }).catch(error => {
        console.error("Error connecting to reader", error)
      })
    }).catch(error => {
      console.error("Error discovering readers", error)
    })
#

so both of them are just placed inside the footer of our layout file

#

There is also just the javascript code:

    function fetchConnectionToken(connectionTokenUrl) {
      console.log("Currently: fetchConnectionToken")
      return () => {
        // Do not cache or hardcode the ConnectionToken. The SDK manages the ConnectionToken's lifecycle.
        return fetch(connectionTokenUrl, {method: "POST"})
          .then(function (response) {
            return response.json();
          })
          .then(function (data) {
            return data.token;
          });
      }
    }

    const terminal = StripeTerminal.create({
      onFetchConnectionToken: fetchConnectionToken("INTERNAL_URL"),
      onUnexpectedReaderDisconnect: () => {
        console.log("Disconnected")
      },
      onConnectionStatusChange: (data) => {
        console.log("onConnectionStatusChange", {data})
      },
    });


    terminal.discoverReaders().then(discoverResult => {
      const reader = discoverResult.discoveredReaders.find(reader => reader.serial_number === "SERIAL_NUMBER")

      terminal.connectReader(reader).then(connectResult => {
        console.log("Connected to reader", connectResult)
      }).catch(error => {
        console.error("Error connecting to reader", error)
      })
    }).catch(error => {
      console.error("Error discovering readers", error)
    })

Is just reducted the serial number and our internal url

south frost
#

can you add error handling code in fetchConnectionToken function?

#

to catch any rejected promises?

#

It is possible that fetching connection token is failing

quaint oasis
#

sure

#

takes a few minutes to wait for the timeout happening

#

I updated the fetchConnectionToken function like so:

function fetchConnectionToken(connectionTokenUrl) {
  console.log("Currently: fetchConnectionToken")
  return () => {
    // Do not cache or hardcode the ConnectionToken. The SDK manages the ConnectionToken's lifecycle.
    return fetch(connectionTokenUrl, {method: "POST"})
      .then(function (response) {
        return response.json();
      })
      .then(function (data) {
        return data.token;
      }).catch(function (error) {
        console.error("Error fetching ConnectionToken", error);
        throw error;
      })
  }
}
#

But still getting the unhandled promise error

#

But you can see that the onUnexpectedReaderDisconnect callback is fired but then afterwards the Unhandled promise rejection error still happens.

south frost
#

Gotcha. However, onUnexpectedReaderDisconnect unblocks you right?

Like you can handle that gracefully in the UI and trigger a reconnection flow

quaint oasis
#

At least thats what i wanted to do. The example you are seeing is just a simplified version, to show the issue. But we are creating a react app and there the unhandled exception is an issue, because it causes the react app to crash, or at least go into an error state.

So I need some way of preventing this unhandled error from happening.

#

Thats why I cant handled it gracefully, in our react app. ๐Ÿ˜ฆ

south frost
#

I see. Let me check if I can reproduce

quaint oasis
#

Sure ๐Ÿ™‚

south frost
#

Hmm I see the uncaught promise error but it isn't crashing my react application

I have a state variable that gets updated when onUnexpectedReaderDisconnect is trigger (which conditionally changes the UI on the page)

quaint oasis
#

But do you have a ErrorBoundry set up?

south frost
#

Ah I don't

quaint oasis
#

I'm trying to remove the error boundary on our site, to check

#

Might also be webpacker catching the error.

south frost
#

Yeah I think that'd be a good workaround for now.
I don't think there's a better way to handle this today.

#

I'll make sure to flag this internally though

#

to see if we can make some improvement

quaint oasis
#

Yea so it also happens without error boundary. So wepacker shows the error.

#

So we kind of need this unhandled exception to be somehow handled

south frost
#

Taking a step back, I assume you're working with a smart reader like WisePOS E or S700 here?

quaint oasis
#

not particularly, but it was the sample provided

#

I mean we don't need it today, but i think this should be fixed anyway, it's just an issue if this takes weeks until it's fixed.

#

Then we have to reconsider and look for a different solution.

south frost
#

Yup I agree, I'll flag this internally and see what the terminal team says. You could write in via following in case you want to stay updated on the progress
https://support.stripe.com/?contact=true

Overall IMO, Server-driven flow is better compared to JS as it eliminates the connection requirements around SDK and the Reader as well as simplifies the code you'd need to work with. I'd recommend just giving it a go to see if you find it better.

quaint oasis
#

What do i need to do, to get updated, the link just gets me to artices site

#

And maybe we'll take a look at the serverside approach the next couple of days.

quaint oasis
#

But yea it would be really awesome if you guys could fix this, since for the server driven approach, we would have too rewrite a portion of our app.

#

But could you keep me up to date, the progress?

elfin lionBOT