XRPLF / xrpl.js

A JavaScript/TypeScript API for interacting with the XRP Ledger in Node.js and the browser
https://xrpl.org/
1.22k stars 512 forks source link

2.0@beta error TypeError: Right-hand side of 'instanceof' is not an object #1691

Closed dangell7 closed 3 years ago

dangell7 commented 3 years ago

I'm not exactly sure what has changed as the docs are still in PR, but when I try client.connect() in a web pack application I get the following error:

TypeError: Right-hand side of 'instanceof' is not an object

if I leave out connect, then I get a NotConnectedError error.

Any ideas?

natenichols commented 3 years ago

Hi @dangell7. Thanks for trying out the beta and for opening an issue.

Could you give us a little more information regarding the environment you're using xrpl.js in and/or a code snippet to help us reproduce the issue?

Thanks again! Nathan

dangell7 commented 3 years ago

Webpack Config Common Resolve:

resolve: {
    symlinks: false,
    fallback: {
      fs: false,
      net: false,
      tls: false,
      dgram: false,
      child_process: false,
      buffer: require.resolve('buffer'),
      util: require.resolve('util'),
      path: require.resolve('path-browserify'),
      https: require.resolve('https-browserify'),
      crypto: require.resolve('crypto-browserify'),
      stream: require.resolve('stream-browserify'),
      assert: require.resolve('assert-browserify'),
      http: require.resolve('stream-http'),
      os: require.resolve('os-browserify/browser'),
      zlib: require.resolve("browserify-zlib"),
    },
    extensions: ['.mjs', '.jsx', '.js', '.json', '.css'],
    modules: ['node_modules', PATHS.app],
  },

Package.json:

"dependencies": {
    "@babel/core": "^7.12.9",
    "@babel/plugin-proposal-class-properties": "^7.14.5",
    "@babel/plugin-proposal-decorators": "^7.15.4",
    "@babel/plugin-transform-modules-commonjs": "^7.15.4",
    "@babel/plugin-transform-runtime": "^7.15.0",
    "@babel/preset-env": "^7.15.6",
    "@babel/preset-react": "^7.14.5",
    "@babel/register": "^7.15.3",
    "@date-io/moment": "^2.11.0",
    "@emotion/react": "^11.4.1",
    "@emotion/styled": "^11.3.0",
    "@ledgerhq/hw-app-eth": "^6.8.1",
    "@ledgerhq/hw-app-xrp": "^6.7.0",
    "@ledgerhq/hw-transport-webusb": "^6.7.0",
    "@material-ui/core": "^4.12.3",
    "@material-ui/icons": "^4.11.2",
    "@material-ui/lab": "^4.0.0-alpha.60",
    "@material-ui/pickers": "^3.3.10",
    "assert-browserify": "^2.0.0",
    "autosuggest-highlight": "^3.1.1",
    "axios": "^0.21.4",
    "babel-loader": "^8.2.2",
    "browserify-zlib": "^0.2.0",
    "buffer": "^6.0.3",
    "change-case": "^4.1.2",
    "connected-react-router": "^6.9.1",
    "crypto-browserify": "^3.12.0",
    "crypto-js": "^4.1.1",
    "css-loader": "^6.3.0",
    "firebase": "^9.1.0",
    "formik": "^2.2.9",
    "http-proxy": "^1.18.1",
    "https-browserify": "^1.0.0",
    "immer": "^9.0.6",
    "install": "^0.13.0",
    "ipfs-core": "^0.11.0",
    "js-cookie": "^3.0.1",
    "jss": "^10.8.0",
    "jss-rtl": "^0.3.0",
    "moment": "^2.29.1",
    "morgan": "^1.10.0",
    "notistack": "^2.0.2",
    "nprogress": "^0.2.0",
    "os-browserify": "^0.3.0",
    "path-browserify": "^1.0.1",
    "postcss-import": "^14.0.2",
    "process": "^0.11.10",
    "prop-types": "^15.7.2",
    "react": "^17.0.2",
    "react-app-polyfill": "^2.0.0",
    "react-autosuggest": "^10.1.0",
    "react-dom": "^17.0.2",
    "react-dropzone": "^11.4.2",
    "react-feather": "^2.0.9",
    "react-helmet": "^6.1.0",
    "react-idle-timer": "^4.6.4",
    "react-json-view": "^1.21.3",
    "react-markdown": "^7.0.1",
    "react-perfect-scrollbar": "^1.5.8",
    "react-redux": "^7.2.5",
    "react-router": "^5.2.1",
    "react-router-dom": "^5.3.0",
    "redux": "^4.1.1",
    "redux-logger": "^3.0.6",
    "redux-thunk": "^2.3.0",
    "ripple-binary-codec": "^1.1.3",
    "ripple-keypairs": "^1.0.3",
    "ripple-lib": "^1.10.0",
    "stream-browserify": "^3.0.0",
    "stream-http": "^3.2.0",
    "style-loader": "^3.3.0",
    "util": "^0.12.4",
    "web3": "^1.5.3",
    "webpack": "^5.54.0",
    "webpack-cli": "^4.8.0",
    "webpack-dev-middleware": "^5.2.1",
    "webpack-dev-server": "^4.3.0",
    "webpack-hot-middleware": "^2.25.1",
    "webpack-merge": "^4.2.2",
    "xrpl": "^2.0.0-beta.3",
    "yup": "^0.32.9"
  },

getXrpl.js using ripple-lib

import { RippleAPI } from 'ripple-lib';

const getRippleSession = new Promise(((resolve, reject) => {
    let results;
    const url = process.env.XRP_NETWORK_URL;
    const api = new RippleAPI({
      server: url
    });
    api.on('error', (errorCode, errorMessage) => {
      reject(errorMessage);
      return;
    });
    api.on('connected', () => {
      results = {
          api,
      };
      resolve(results);
      return;
    });
    api.on('disconnected', (code) => {
      // code - [close code](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) sent by the server
      // will be 1000 if this was normal closure
      console.warn('disconnected, code:', code);
      return;
    });

    api.connect().then(() => {
        results = {
            api,
        };
        resolve(results);
        return;
    }).catch((error) => {
      reject(error);
    });
}));

export default getRippleSession;

The above code works.

getXrpl using xrpl:

import { Client } from 'xrpl';

const getRippleSession = new Promise(((resolve, reject) => {
    let results;
    const url = process.env.XRP_NETWORK_URL;
    const api = new Client(url);
    api.on('error', (errorCode, errorMessage) => {
      reject(errorMessage);
      return;
    });
    api.on('connected', () => {
      results = {
          api,
      };
      resolve(results);
      return;
    });
    api.on('disconnected', (code) => {
      // code - [close code](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) sent by the server
      // will be 1000 if this was normal closure
      console.warn('disconnected, code:', code);
      return;
    });

    api.connect().then(() => {
        results = {
            api,
        };
        resolve(results);
        return;
    }).catch((error) => {
      reject(error);
    });
}));

export default getRippleSession;

Notice the resolve fallbacks. net, tls and fs were added for xrpl js.

dangell7 commented 3 years ago

So if I change the RippleAPI to Client directly without changing anything else I get:

ValidationError: server URI must start withwss://,ws://,wss+unix://, orws+unix://.

The url is wss://s.altnet.rippletest.net:51233 so that error isn't clear.

Then if I change the Client to Client(url) instead of Client({ server: url }) I get the error that created the issue.

dangell7 commented 3 years ago

Here is the full error:

services.js:113 TypeError: Right-hand side of 'instanceof' is not an object
    at initAsClient (websocket.js:618)
    at new WebSocket (websocket.js:83)
    at createWebSocket (connection.js:76)
    at Connection.<anonymous> (connection.js:142)
    at Generator.next (<anonymous>)
    at connection.js:8
    at new Promise (<anonymous>)
    at __webpack_modules__../node_modules/xrpl/dist/npm/client/connection.js.__awaiter (connection.js:4)
    at Connection.connect (connection.js:123)
    at Client.<anonymous> (index.js:191)
mvadari commented 3 years ago

Is this error from using React, or through regular webpacked code?

natenichols commented 3 years ago

@dangell7 Thank you so much for opening an issue, and providing a lot of relevant information about the issue.

I was able to reproduce the issue locally, and should have a fix.

It looks like the fix is the same as the fix for another issue we saw with react this morning. We have this fix up in PR at #1694.

We'll post in this thread when we publish a beta.4 with this fix in it.

Thanks again, Nathan

dangell7 commented 3 years ago

You guys ROCK!!

natenichols commented 3 years ago

2.0.0-beta.4 has been published. It appears to resolve this issue on my machine.

Let us know if this works for you when you get a chance to try it out.

dangell7 commented 3 years ago

WOW. What a turn around time.. All good here.. Popping a few errors. I'll post them here but no need to keep this open as the new docs likely already point to the new functions.

dangell7 commented 3 years ago

Here is the list of functions I am missing..

getAccountInfo getAccountObjects

deriveAddress existed on both keypairs and the api. Now only keypairs. Probably not an issue for most.

@natenichols I read your review comment about balances vs account_info. I have a feeling I will end up using balances more than account info. I can also tell you that this is because I now use currencies more that the native XRP token. So I would assume new developers will gravitate to account_info and later transition to balances when they have a multi currency use case.

dangell7 commented 3 years ago

result.api.sign not a function. Probably more me making deprecated calls but this info might be useful for others.

mvadari commented 3 years ago

We're still working on the full migration docs, but here's a draft of that: https://github.com/XRPLF/xrpl-dev-portal/blob/xrpljs2.0/content/references/xrpljs2-migration-guide.md

JST5000 commented 3 years ago

@dangell7 I'm on the team with @mvadari and @natenichols and I'm doing interviews to see what migration problems folks run into. If you're interested, we can migrate some code together 🙂 (Just send me an email at jmills@ripple.com and we can sort out a time) - If you don't want to, no pressure though!

dangell7 commented 3 years ago

So just to update we had a meeting today that went really well. I have updated my code base.

getAccountInfo getAccountObjects

Were simple and I do like how the ws/rpc call parameters are what is put into the request function on the client. It forces developers to have a general understanding of the api without just calling functions willy nilly.

prepareTx signTx submitTx

These were a little different.

return api.sign(tx, seed)

became

const wallet = Wallet(seed);
const signedTx  = wallet.signTransaction(tx);
tx.signedTransaction = signedTx;
return tx;

A few things to note here is that prepareTransaction using the client, doesn't return an object with an included txJSON object, it returns the final json transaction.

I can elaborate. Before prepareTransaction would return something like {txJSON: {new tx stuff}, tx: {old tx stuff}} where now it returns the "autofilled" tx. Just a minor change. Instead of sign(tx.txJSON) it became signTransaction(tx).

Another is that wallet.signTransaction doesn't return the full transaction but the signedTransaction.

Finally submitTransaction just returned a different kind of result but no issues with that. Still got all the info I need. I also like the outside parameters if I dont care about the result data.

Thanks again for your time.

lemoyim commented 2 years ago

In case somebody here has the same problem with xrpl.js and SvelteKit (or other Vite-powered FE): Vite seems to ignore the browser field for ws and just tries to use ws instead of native browser websocket API, which throws an error.

https://github.com/XRPLF/xrpl.js/blob/main/packages/xrpl/package.json#L20-L22

A workaround of putting an alias for it manually works (in your vite.config.js):

resolve: {
        alias: {
            // your other aliases
                        // ...
            ws: './node_modules/xrpl/dist/npm/client/WSWrapper.js'
        }
    },

Vite's repo is aware of that https://github.com/vitejs/vite/issues/7576#issuecomment-1202074349