e is not a constructor - WalletConnectProvider model not working - javascript

Metamask is working perfectly.
BinanceChainWallet is working perfectly.
WalletConnect provider (model: QR - desktop/mobile wallet support), not working when I click on Wallet-Connect model on the front-end it give me this error only.
Platform on:
Framework: Laravel 8.0
JS
The problem is in this file (LaravelWeb3Scripts.php/walletconnect.ts) - this file is the one used for getting providers models.
Vendor/Provider used
https://github.com/sawirricardo/laravel-web3
Wallet-Connect Model repo https://github.com/WalletConnect/web3modal/blob/master/docs/providers/walletconnect.md
Console Log error (Chrome Developer Tools):
Uncaught (in promise) TypeError: e is not a constructor
at walletconnect.ts:31:22
at tslib.es6.js:100:1
at Object.next (tslib.es6.js:81:45)
at tslib.es6.js:74:1
at new Promise (<anonymous>)
at Module.A (tslib.es6.js:70:1)
at walletconnect.ts:15:44
at new Promise (<anonymous>)
at t.default (walletconnect.ts:15:10)
at e.<anonymous> (providers.ts:201:30)
walletconnect.ts - providers.ts - tslib.es6.js are imported from cdns
File: walletconnect.ts
import { IAbstractConnectorOptions, getChainId } from "../../helpers";
export interface IWalletConnectConnectorOptions
extends IAbstractConnectorOptions {
infuraId?: string;
rpc?: { [chainId: number]: string };
bridge?: string;
qrcode?: boolean;
}
const ConnectToWalletConnect = (
WalletConnectProvider: any,
opts: IWalletConnectConnectorOptions ) => {
return new Promise(async (resolve, reject) => {
let bridge = "https://bridge.walletconnect.org";
let qrcode = true;
let infuraId = "";
let rpc = undefined;
let chainId = 1;
console.log('wallet connect'); // todo remove dev item
if (opts) {
bridge = opts.bridge || bridge;
qrcode = typeof opts.qrcode !== "undefined" ? opts.qrcode : qrcode;
infuraId = opts.infuraId || "";
rpc = opts.rpc || undefined;
chainId =
opts.network && getChainId(opts.network) ? getChainId(opts.network) : 1;
}
const provider = new WalletConnectProvider({
bridge,
qrcode,
infuraId,
rpc,
chainId
});
try {
await provider.enable();
resolve(provider);
} catch (e) {
reject(e);
}
});
};
export default ConnectToWalletConnect;
File: LaravelWeb3Scripts.php
<?php
namespace Sawirricardo\LaravelWeb3\Components;
use Illuminate\View\Component;
class LaravelWeb3Scripts extends Component {
/**
* Create a new component instance.
*
* #return void
*/
public function __construct() {
//
}
/**
* Get the view / contents that represent the component.
*
* #return \Illuminate\Contracts\View\View|\Closure|string
*/
public function render() {
return <<<'blade'
<script>
class LaravelWeb3 {
constructor() {
this._provider = null;
this.reloadAfterFetching = true;
this.alertUserIfMetamaskIsNotInstalled = true;
this.contracts = #json(config('web3.contracts'));
this.web3ModalOptions = {
cacheProvider: true,
disableInjectedProvider: false,
providerOptions: {
binancechainwallet: {
package: true
},
walletconnect: {
package: WalletConnectProvider,
options: {
infuraId: "*********// hidden for post",
},
},
},
};
}
async onConnect() {
try {
const web3Modal = this.prepareWeb3Modal();
const provider = await web3Modal.connect();
provider.on("accountsChanged", async (accounts) => {
console.log("accountsChanged", accounts);
web3Modal.clearCachedProvider();
await this.fetchAccount(provider);
if (this.reloadAfterFetching) window.location.reload();
});
provider.on("chainChanged", async (chainId) => {
console.log("chainChanged", chainId);
web3Modal.clearCachedProvider();
await this.fetchAccount(provider);
if (this.reloadAfterFetching) window.location.reload();
});
provider.on("connect", ( { chainId }) => {
console.log("connect", chainId);
});
provider.on("disconnect", ( { code, message }) => {
console.log("disconnect", code, message);
});
await this.fetchAccount(provider);
if (this.reloadAfterFetching) window.location.reload();
} catch (e) {
console.log({ e });
}
}
async fetchAccount(web3Provider) {
const provider = new ethers.providers.Web3Provider(web3Provider);
const message = await(await(await fetch("/_web3/users/signature", {
method: "get",
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": "{{ csrf_token() }}",
},
})).json()).message;
await fetch("/_web3/users",{
method:'post',
body: JSON.stringify({
signature: await provider.getSigner().signMessage(message),
address: await provider.getSigner().getAddress(),
}),
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": "{{ csrf_token() }}",
},
})
this._provider = provider;
}
async onDisconnect() {
this._provider = null;
const web3Modal = this.prepareWeb3Modal();
await web3Modal.clearCachedProvider();
await fetch("/_web3/users/logout",{
method: "delete",
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": "{{ csrf_token() }}",
},
});
if (this.reloadAfterFetching) window.location.reload();
}
async getProvider() {
if (!this._provider) {
const web3Modal = this.prepareWeb3Modal();
const web3Provider = await web3Modal.connect();
this._provider = new ethers.providers.Web3Provider(web3Provider);
}
return this._provider;
}
prepareWeb3Modal () {
let Web3Modal, WalletConnectProvider;
// if (!(window.web3 || window.ethereum) && this.alertUserIfMetamaskIsNotInstalled) {
// alert(`Please install Metamask first`);
// return;
// }
if (window.Web3Modal.default) {
Web3Modal = window.Web3Modal.default;
}
if (window.WalletConnectProvider) {
WalletConnectProvider = window.WalletConnectProvider.default;
}
const web3Modal = new Web3Modal(this.web3ModalOptions);
return web3Modal;
}
addContract(address,contract) {
this.contracts = [...this.contracts, { address, contract }];
}
}
window.laravelWeb3 = new LaravelWeb3();
</script>
blade;
}
}

Related

The fetch code in onNewScanResult is executed more than once once a QR code has been scanned, and also updating database. How to stop it from running?

executing the fetch code in onNewScanResult multiplt time and hence updating the database accordingly................
initialization of qr scanner.........
this.html5QrcodeScanner = new Html5QrcodeScanner(
qrcodeRegionId,
config,
verbose
); ```Executing scanner when qrcode is scanned```
this.html5QrcodeScanner.render(
this.props.qrCodeSuccessCallback,
this.props.qrCodeErrorCallback
);
}
}
this is main qr code class........
class QrCode extends React.Component {
constructor() {
super();
this.state = {
decodedResults: [],
};
this.onNewScanResult = this.onNewScanResult.bind(this);
}
this is where the executing multiple time is happing.......
onNewScanResult(decodedText, decodedResult) {
`geting data from loacal storage as we saved data earlier in the process about acess level`
const qrRes = decodedText;
const obj = JSON.parse(qrRes);
const token = localStorage.getItem("user");
const userData = JSON.parse(token);
const username = userData[0].userId;
const accesslevel = userData[0].accessLevel;
const result = JSON.parse(qrRes);
const ele = result.ele_name;
const newdata = { ele, username, accesslevel };
const data = {
Element_detail: obj,
accessLevel: newdata.accesslevel,
};
const verifyUser = localStorage.getItem("accessLeveldetails");
const accessdetail = JSON.parse(verifyUser);
```checking is user is verified or not```......
`checking the acess level you can ignore the checking focus on fetch part`....
This particular part is we have to stop executing multiple time so database is only entered with one value
if (accessdetail.accessLevel === data.accessLevel) {
try { ``` this fetch is updating database with multiple entries```
fetch(
data.accessLevel === 20
? `/v0/all_elements_image`
: `/v0/${accessdetail.msg}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(obj),
}
).then((res) => {
console.log(res);
if (!res) {
throw res;
}
return res.json();
});
} catch (error) {
console.log("Error:", error);
}
} else {
alert("WRONG USER");
}
}
}

React Native - {"name":"Invariant Violation","framesToPop":1}

I'm trying to implement meilisearch api in React native and it is working fine with my simulator and after I publish the app some of the users cannot see the data returning from meilisearch, the error is
{"name":"Invariant Violation","framesToPop":1}
This is my code
Meilisearch.js
import axios from 'axios';
import { meilisearchConfig } from '../Config';
const MeilisearchApi = async (payload, success, failed) => {
try {
const response = await axios({
method: 'post',
url: `${meilisearchConfig?.host}indexes/activities/search`,
data: payload,
headers: {
'X-Meili-API-Key': meilisearchConfig?.apiKey,
},
});
success?.(response?.data);
} catch (err) {
failed?.(err);
}
};
export default MeilisearchApi;
This is the normalizer for returning data
import moment from 'moment';
import { IActivity, IByDateGroupFilter } from 'reducers/types';
export const activityNormalizer = (state, { hits, offset }) => {
const {
melisearchActivityData: { byDate, dates, all },
} = state;
const isRefreshing = offset === 0;
const newAll = isRefreshing ? hits : [...all, ...hits];
const datesNew: string[] = isRefreshing ? [] : dates;
const byDateNew: any = isRefreshing ? {} : byDate;
const byDateGroup: IByDateGroupFilter[] = [];
hits.forEach((activity: IActivity) => {
const date = getFormattedDate(activity.created_at);
if (byDateNew[date]) byDateNew[date].push({ ...activity });
else {
byDateNew[date] = [{ ...activity }];
datesNew.push(date);
}
});
Object.keys(byDateNew).forEach((key) => {
byDateGroup.push({
title: key,
data: byDateNew[key],
});
});
return {
dates: datesNew,
byDate: byDateNew,
byDateGroup,
all: newAll,
};
};
This is how i call my Meilisearch API method
MeilisearchApi(
{
q: search,
filters: filters,
offset: newOffset,
limit: PAGE_SIZE,
},
({ hits }: { hits: any[] }) => {
setDataLoaded(true);
setMelisearchActivitiesToRedux({ hits, offset: newOffset });
if (newOffset === 0) {
sectionList?.current?.scrollToLocation({
itemIndex: 1,
});
}
},
(err: any) => {
setDataLoaded(true);
log(err)
},
);
No Idea how this error happens, when users kill the app and logging again this works fine

Receiving Undefined Error for Javascript Program when Updating for CRUD Frontend

I created a frontend javascript for my ruby on rails backend and I am receiving the following error when I try to update a book title:
Error: app.js:65 Uncaught TypeError: Cannot read property 'renderUpdateForm' of undefined
at App.handleEditClick (app.js:65)
I am receiving books titles and their authors from a backend api.
Here is the code:
document.addEventListener('DOMContentLoaded', () => {
const app = new App();
app.attachEventListeners();
app.adapter.fetchAuthors().then(app.createAuthors);
app.adapter.fetchBooks().then(app.createBooks);
});
class Book {
constructor(data) {
this.id = data.id;
this.title = data.title;
const author = Author.findById(data.author_id);
this.author = author.name;
Book.all.push(this);
}
update({ title }) {
this.title = title;
}
renderListItem() {
return `
<li>
<h3>${this.title} - ${this.author}
<button data-id=${this.id}>update</button>
<button data-id=${this.id}>delete</button>
</h3>
</li>`;
}
renderUpdateForm() {
return `
<form data-id='${this.id}'>
<label>Title</label>
<p>
<input type="text" value="${this.title}" />
</p>
<button type='submit'>Save Book</button>
</form>
`;
}
static findById(id) {
return this.all.find(book => book.id === id);
}
}
Book.all = [];
class App {
constructor() {
this.adapter = new Adapter();
this.handleEditClick = this.handleEditClick.bind(this);
this.handleEditClick = this.handleDeleteClick.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
this.createBooks = this.createBooks.bind(this);
this.createAuthors = this.createAuthors.bind(this);
this.addBooks = this.addBooks.bind(this);
}
attachEventListeners() {
$('#books-list').on('click', 'button', this.handleEditClick);
$('#books-list').on('click', 'button', this.handleDeleteClick);
$('#update').on('submit', 'form', this.handleFormSubmit);
}
createBooks(books) {
books.forEach(book => {
new Book(book);
});
console.log(this);
this.addBooks();
}
createAuthors(authors) {
authors.forEach(author => {
new Author(author);
});
console.log(this);
this.addAuthors();
}
addBooks() {
$('#books-list').empty();
Book.all.forEach(book => $('#books-list').append(book.renderListItem()));
}
addAuthors() {
$('#authors-list').empty();
Author.all.forEach(author => $('#authors-list').append(author.renderListItem()));
}
handleFormSubmit(e) {
e.preventDefault();
const id = e.target.dataset.id;
const book = Book.findById(id);
const title = $(e.target)
.find('input')
.val();
const bodyJSON = { title };
this.adapter.updateBook(book.id, bodyJSON).then(updatedBook => {
const book = Book.findById(updatedBook.id);
book.update(updatedBook);
this.addBooks();
});
}
handleEditClick(e) {
const id = e.target.dataset.id;
const book = Book.findById(id);
$('#update').html(book.renderUpdateForm());
}
handleDeleteClick(e) {
const id = e.target.dataset.id;
const book = Book.findById(id);
const title = $(e.target)
.find('input')
.val();
const bodyJSON = { title };
this.adapter.deleteBook(book.id, bodyJSON);
}
}
class Adapter {
constructor() {
this.baseUrl = 'http://localhost:3000/api/v1';
this.headers = {
'Content-Type': 'application/json',
Accept: 'application/json'
};
}
fetchBooks() {
return this.get(`${this.baseUrl}/books`);
}
fetchAuthors() {
return this.get(`${this.baseUrl}/authors`);
}
updateBook(id, body) {
return this.patch(`${this.baseUrl}/books/${id}`, body);
}
deleteBook(id, body) {
return this.delete(`${this.baseUrl}/books/${id}`, body);
}
get(url) {
return fetch(url).then(res => res.json());
}
patch(url, body) {
return fetch(url, {
method: 'PATCH',
headers: this.headers,
body: JSON.stringify(body)
}).then(res => res.json());
}
delete(url, body) {
return fetch(url, {
method: 'DELETE',
headers: this.headers,
body: JSON.stringify(body)
}).then(res => res.json());
}
}
const book = Book.findById(id);
returns undefined.
Which means there is no entry with that id. e.target.dataset.id probably has a different value than expected (console.log is your friend).
To guard against this type of error (so your app doesn't break when you're using an invalid/non-existent id), you could just wrap next line in a condition:
handleEditClick(e) {
const id = e.target.dataset.id;
const book = Book.findById(id);
if (book) {
$('#update').html(book.renderUpdateForm());
}
}
Better checks are whether the result has a function named renderUpdateForm:
if (book && typeof book.renderUpdateForm === 'function') {
$('#update').html(book.renderUpdateForm())
}
or if it is a Book instance:
if (book instanceof Book) {
$('#update').html(book.renderUpdateForm())
}

Typescript Class Variable Not Updating / Retaining Value

I am trying to create a class that will fetch / cache users from my Firestore database. For some reason, I can't seem to save or expose the previous promise that was created. Here is my class:
export class UserCache {
private cacheTimeMilliseconds: number = 600000;
private userCache: any = {};
public getCacheUser(userid: string): Promise<User> {
return new Promise((resolve, reject) => {
let d = new Date();
d.setTime(d.getTime() - this.cacheTimeMilliseconds);
if (this.userCache[userid] && this.userCache[userid].complete && this.userCache[userid].lastAccess > d.getTime()) {
console.log("User cached");
resolve(this.userCache[userid].user);
}
console.log("Need to cache user");
this.userCache[userid] = {
complete: false
};
this.getSetUserFetchPromise(userid).then((data) => {
let user: User = <User>{ id: data.id, ...data.data() };
this.userCache[userid].user = user;
this.userCache[userid].complete = true;
this.userCache[userid].lastAccess = Date.now();
resolve(user);
});
});
}
private getSetUserFetchPromise(userid: string): Promise<any> {
console.log(this.userCache[userid]);
if (this.userCache[userid] && this.userCache[userid].promise) {
return this.userCache[userid].promise;
} else {
console.log("Creating new user fetch request.");
this.userCache[userid].promise = firestore().collection('users').doc(userid).get();
console.log(this.userCache[userid]);
return this.userCache[userid].promise;
}
}
}
Logs: (there are only 2 unique users, so should only be creating 2 new requests)
In the logs I can see that the promise is getting set in getSetUserFetchPromise, but the next time the function is called, the property is no longer set. I suspect it is either a scope or concurrency issue, but I can't seem to get around it.
I am calling getCacheUser in a consuming class with let oCache = new UserCache() and oCache.getCacheUser('USERID')
Edit following Tuan's answer below
UserCacheProvider.ts
import firestore from '#react-native-firebase/firestore';
import { User } from '../static/models';
class UserCache {
private cacheTimeMilliseconds: number = 600000;
private userCache: any = {};
public getCacheUser(userid: string): Promise<User> {
return new Promise((resolve, reject) => {
let d = new Date();
d.setTime(d.getTime() - this.cacheTimeMilliseconds);
if (this.userCache[userid] && this.userCache[userid].complete && this.userCache[userid].lastAccess > d.getTime()) {
console.log("User cached");
resolve(this.userCache[userid].user);
}
console.log("Need to cache user");
this.userCache[userid] = {
complete: false
};
this.getSetUserFetchPromise(userid).then((data) => {
let user: User = <User>{ id: data.id, ...data.data() };
this.userCache[userid].user = user;
this.userCache[userid].complete = true;
this.userCache[userid].lastAccess = Date.now();
resolve(user);
});
});
}
private getSetUserFetchPromise(userid: string): Promise<any> {
console.log(this.userCache[userid]);
if (this.userCache[userid] && this.userCache[userid].promise) {
return this.userCache[userid].promise;
} else {
console.log("Creating new user fetch request.");
this.userCache[userid].promise = firestore().collection('users').doc(userid).get();
console.log(this.userCache[userid]);
return this.userCache[userid].promise;
}
}
}
const userCache = new UserCache();
export default userCache;
ChatProvider.ts (usage)
let promises = [];
docs.forEach(doc => {
let message: Message = <Message>{ id: doc.id, ...doc.data() };
promises.push(UserCacheProvider.getCacheUser(message.senderid).then((oUser) => {
let conv: GCMessage = {
_id: message.id,
text: message.messagecontent,
createdAt: new Date(message.messagedate),
user: <GCUser>{ _id: oUser.id, avatar: oUser.thumbnail, name: oUser.displayname }
}
if (message.type && message.type == 'info') {
conv.system = true;
}
if (message.messageattachment && message.messageattachment != '') {
conv.image = message.messageattachment;
}
return conv;
}));
});
Promise.all(promises).then((values) => {
resolve(values);
});
Without seeing the calling code, it could be that getCacheUser is called twice before firestore resolves.
As an aside, I think refactoring the class may make debugging easier. I wonder why it caches the user, promise completion status, and the promise itself. Why not just cache the promise, something like:
interface UserCacheRecord {
promise: Promise<User>
lastAccess: number
}
export class UserCache {
private cacheTimeMilliseconds: number = 600000;
private userCache: { [userid: string]: UserCacheRecord } = {};
public async getCacheUser(userid: string): Promise<User> {
let d = new Date();
const cacheExpireTime = d.getTime() - this.cacheTimeMilliseconds
if (this.userCache[userid] && this.userCache[userid].lastAccess > cacheExpireTime) {
console.log("User cached");
return this.userCache[userid].promise
}
console.log("Need to cache user");
this.userCache[userid] = {
promise: this.getUser(userid),
lastAccess: Date.now()
}
return this.userCache[userid].promise
}
private async getUser(userid: string): Promise<User> {
const data = firestore().collection('users').doc(userid).get();
return <User>{ id: data.id, ...data.data() };
}
}
Currently, you create new UserCache everytime you access cache users. You have to export the instance of UserCache class, so just single instance is used for your app.
UserCache.ts
class UserCache {
}
const userCache = new UserCache();
export default userCache;
SomeFile.ts
import UserCache from './UserCache';
UserCache.getCacheUser('USERID')
Update
Added some tests
class UserCache {
userCache = {};
getUser(id) {
return new Promise((resolve, reject) => {
if (this.userCache[id]) {
resolve({
...this.userCache[id],
isCache: true,
});
}
this.requestUser(id).then(data => {
resolve(data);
this.userCache[id] = data;
});
});
}
requestUser(id) {
return Promise.resolve({
id,
});
}
}
const userCache = new UserCache();
export default userCache;
userCache.test.ts
import UserCache from '../test';
describe('Test user cache', () => {
test('User cached successfully', async () => {
const user1: any = await UserCache.getUser('test1');
expect(user1.isCache).toBeUndefined();
const user2: any = await UserCache.getUser('test1');
expect(user2.isCache).toBe(true);
});
});

Stub dependent function with sinon and proxyquire does not print stub result

I wrote a unit test for _getuser() but I don't see console.log print stub result.Also test coverage shows line 'let user = result.user;
console.log('User'+JSON.stringify(result));' is uncovered.Why stub result does not print in console log in getUser() function in LogInCommand class.
I see result shows undefined in unit test.
// userApi.js
'use strict';
const config = require('../../config/config');
const api = require('./apiService');
class UserApi {
constructor() {
}
getUser(userId) {
return api.get({
url: config.url,
qs: {
includeInactive: true,
id: userId,
startIndex: 0,
maxResults: 1
},
headers: {
Accept: 'application/json;',
'Connection': 'Keep-Alive'
}
});
}
}
module.exports = UserApi;
// LoginCommand.js
'use restrict';
const userApi = require('../../api/userApi');
class LogInCommand {
constructor() {
}
async _getUser(userId) {
let result = await new userApi().getUser(userId);
let user = result.user;
console.log('User'+JSON.stringify(result));
return user;
}
}
module.exports = LogInCommand;
//LoginCommand.test.js
describe('Test LogInCommand Class',function(){
it.only('_getUser function should return user', async ()=> {
let apiData= {
user:'abc'
};
let logincmd = proxyquire('../LogInCommand.js', {
userApi : { getUser : Promise.resolve(apiData) },'#noCallThru':true});
let obj= new logincmd();
let result= await obj._getUser(client);
});
});
The proxyquire configuration is incorrect in your current setup. Proxyquire maps the string value passed in a require call to the desired mock/stub values. Try the following instead:
let logincmd = proxyquire('../LogInCommand.js', {
'../../api/userApi' : { getUser : Promise.resolve(apiData) },
'#noCallThru':true
});
Below code worked for me
// userApi.js
'use strict';
const config = require('../../config/config');
const api = require('./apiService');
class UserApi {
constructor() {
}
getUser(userId) {
return api.get({
url: config.url,
qs: {
includeInactive: true,
id: userId,
startIndex: 0,
maxResults: 1
},
headers: {
Accept: 'application/json;',
'Connection': 'Keep-Alive'
}
});
}
}
module.exports = UserApi;
// LoginCommand.js
'use restrict';
const userApi = require('../../api/userApi');
class LogInCommand {
constructor() {
}
async _getUser(userId) {
let result = await new userApi().getUser(userId);
let user = result.user;
console.log('User'+JSON.stringify(result));
return user;
}
}
module.exports = LogInCommand;
//LoginCommand.test.js
describe('Test LogInCommand Class',function(){
it.only('_getUser function should return user', async ()=> {
class userApiStub{
constructor(){}
getUser() {
return Promise.resolve({
user:4
});
}
}
let logincmd = proxyquire('../LogInCommand.js', {
'../../api/userApi' :userApiStub },'#noCallThru':true});
let obj= new logincmd();
let result= await obj._getUser(client);
});
});

Categories

Resources