React, Web3.js & Metaplex: Unable to import `programs.metadata.Metadata` from #metaplex/js - node.js

Issue
Attempting to follow the 'your first request' example here: https://docs.metaplex.com/sdk/js/getting-started#your-first-request
The module referred to in the examples doesn't contain the data needed.
For context, I am using this example to develop the solution explained at step 5 of these instructions: https://gist.github.com/creativedrewy/9bce794ff278aae23b64e6dc8f10e906
Steps to replicate
Step 1) I install the #metaplex/js package via: yarn add #metaplex/js
Step 2) I import programs from the module by placing import { programs } from '#metaplex/js';.
Step 3) I attempt to unpack Metadata from programs via: const { Metadata } = programs.metadata;
At this stage, if I execute npm run start or yarn run start I see the error that the property Metadata of programs.metadata is undefined. When I look in node_modules/#metaplex/js/ I see that the error is correct.
The only mention of metadata in the module is the function used to lookup metadata once you have the URL. The stage I am at is attempting to retrieve the URL, so this package is not useful, despite being the only one referred to in the docs.

To solve the issue, I created an empty react app and added the following dependencies to my package.json file:
"#metaplex/js": "^1.1.1",
"#solana/spl-token": "^0.1.8",
"#solana/web3.js": "^1.24.1",
I then ran npm install inside the app's root directory.
Inside App.js (or index.js if you did not use create-react-app), I unpacked Metadata directly from the metaplex package with the following line, placed at the top of the file:
import { Metadata } from '#metaplex/js';
Beneath all the imports, I added the following code (an edited version of the code from the example in the original question):
const connection = new Connection('devnet');
const tokenPublicKey = 'Gz3vYbpsB2agTsAwedtvtTkQ1CG9vsioqLW3r9ecNpvZ';
const run = async () => {
try {
const ownedMetadata = await Metadata.load(connection, tokenPublicKey);
console.log(ownedMetadata);
} catch {
console.log('Failed to fetch metadata');
}
};
In my implementation, I'm using a button inside my App() function, instead of calling run() directly like in the example:
<button
onClick={run}
>
GALLERY
</button>
Now, when clicking the button, I correctly see the metadata JSON displayed in the console.

Related

How to fix "Error: /home/site/wwwroot/node_modules/canvas/build/Release/canvas.node: invalid ELF header" on NodeJs Azure Functions in Linux?

I am trying to deploy an AzureFunctions in NodeJs but it doesn't work on Azure.
My apllication is a v3 functions running on Linux.
When the deploy is completed, i get this 500 error:
Error:
/home/site/wwwroot/node_modules/canvas/build/Release/canvas.node:
invalid ELF header
Its happen only when I do this imports:
import ChartDataLabels from 'chartjs-plugin-datalabels';
const canvasRenderService = new CanvasRenderService(width, height, chartCallback);
const chartCallback = (ChartJS) => {
ChartJS.register(require('chartjs-plugin-datalabels'))
};
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const { document } = (new JSDOM(`...`)).window;
Would someone help me please?
It works (only) on my machine :(
Edit: It works when I make the deploy by Linux Subsystem.
I hope this will help somebody.
Azure function will not include the Node_modules while deploying into azure. Because Node_modules directory contains very large file. You can include your package.json in you function directory and run npm install as you normally would with Node.js projects using Kudu (https://<function_app_name>.scm.azurewebsites.net )or the Console in the Azure portal.
Check Dependency management for more information.
Refer here Link 1 & Link 2
Any updates on this topic?
Doesn't seem like a valid option for me to manually run npm install via KUDU or some other terminal in a Cloud Function App - especially with Continoues Deployment etc.
Got the same problem while using canvas for barcode generation...

Jest tests - Please add 'import "reflect-metadata"' to the top of your entry point

I'm developing an application using dependency injection with tsyringe. That's the example of a service that receives the repository as a dependency:
import { injectable, inject } from 'tsyringe'
import IAuthorsRepository from '#domains/authors/interfaces/IAuthorsRepository'
#injectable()
export default class ListAuthorsService {
constructor (
#inject('AuthorsRepository')
private authorsRepository: IAuthorsRepository
) {}
And the dependencies container:
import { container } from 'tsyringe'
import IAuthorsRepository from '#domains/authors/interfaces/IAuthorsRepository'
import AuthorsRepository from '#domains/authors/infra/typeorm/repositories/AuthorsRepository'
container.registerSingleton<IAuthorsRepository>(
'AuthorsRepository',
AuthorsRepository
)
export default container
In the tests, I don't want to use the dependencies registered on the container, but instead, to pass a mock instance via parameter.
let authorsRepository: AuthorsRepositoryMock
let listAuthorsService: ListAuthorsService
describe('List Authors', () => {
beforeEach(() => {
authorsRepository = new AuthorsRepositoryMock()
listAuthorsService = new ListAuthorsService(authorsRepository)
})
But I'm receiving the following error:
tsyringe requires a reflect polyfill. Please add 'import
"reflect-metadata"' to the top of your entry point.
What I thought was - "I may need to import the reflect-metadata package before executing the tests". So I created a jest.setup.ts which imports the reflect-metadata package. But another error occurs:
The instance of the repository is somehow undefined.
I would like to run my tests in peace.
First create in root of your project an jest.setup.ts.
In your jest.config.js, search for this line:
// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],
uncomment, and add your jest.setup.ts file path.
// A list of paths to modules that run some code to configure or set up the testing framework before each test
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
Now import the reflect-metadata in jest.setup.ts:
import 'reflect-metadata';
And run tests again.
I went through the same problem here and refactoring the test find out that it has to import the dependencies first and then the class of service that will be tested

How to import a node module inside an angular web worker?

I try to import a node module inside an Angular 8 web worker, but get an compile error 'Cannot find module'. Anyone know how to solve this?
I created a new worker inside my electron project with ng generate web-worker app, like described in the above mentioned ng documentation.
All works fine until i add some import like path or fs-extra e.g.:
/// <reference lib="webworker" />
import * as path from 'path';
addEventListener('message', ({ data }) => {
console.log(path.resolve('/'))
const response = `worker response to ${data}`;
postMessage(response);
});
This import works fine in any other ts component but inside the web worker i get a compile error with this message e.g.
Error: app/app.worker.ts:3:23 - error TS2307: Cannot find module 'path'.
How can i fix this? Maybe i need some additional parameter in the generated tsconfig.worker.json?
To reproduce the error, run:
$ git clone https://github.com/hoefling/stackoverflow-57774039
$ cd stackoverflow-57774039
$ yarn build
Or check out the project's build log on Travis.
Note:
1) I only found this as a similar problem, but the answer handles only custom modules.
2) I tested the same import with a minimal electron seed which uses web workers and it worked, but this example uses plain java script without angular.
1. TypeScript error
As you've noticed the first error is a TypeScript error. Looking at the tsconfig.worker.json I've found that it sets types to an empty array:
{
"compilerOptions": {
"types": [],
// ...
}
// ...
}
Specifying types turns off the automatic inclusion of #types packages. Which is a problem in this case because path has its type definitions in #types/node.
So let's fix that by explicitly adding node to the types array:
{
"compilerOptions": {
"types": [
"node"
],
// ...
}
// ...
}
This fixes the TypeScript error, however trying to build again we're greeted with a very similar error. This time from Webpack directly.
2. Webpack error
ERROR in ./src/app/app.worker.ts (./node_modules/worker-plugin/dist/loader.js!./src/app/app.worker.ts)
Module build failed (from ./node_modules/worker-plugin/dist/loader.js):
ModuleNotFoundError: Module not found: Error: Can't resolve 'path' in './src/app'
To figure this one out we need to dig quite a lot deeper...
Why it works everywhere else
First it's important to understand why importing path works in all the other modules. Webpack has the concept of targets (web, node, etc). Webpack uses this target to decide which default options and plugins to use.
Ordinarily the target of a Angular application using #angular-devkit/build-angular:browser would be web. However in your case, the postinstall:electron script actually patches node_modules to change that:
postinstall.js (parts omitted for brevity)
const f_angular = 'node_modules/#angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/browser.js';
fs.readFile(f_angular, 'utf8', function (err, data) {
var result = data.replace(/target: "electron-renderer",/g, '');
var result = result.replace(/target: "web",/g, '');
var result = result.replace(/return \{/g, 'return {target: "electron-renderer",');
fs.writeFile(f_angular, result, 'utf8');
});
The target electron-renderer is treated by Webpack similarily to node. Especially interesting for us: It adds the NodeTargetPlugin by default.
What does that plugin do, you wonder? It adds all known built in Node.js modules as externals. When building the application, Webpack will not attempt to bundle externals. Instead they are resolved using require at runtime. This is what makes importing path work, even though it's not installed as a module known to Webpack.
Why it doesn't work for the worker
The worker is compiled separately using the WorkerPlugin. In their documentation they state:
By default, WorkerPlugin doesn't run any of your configured Webpack plugins when bundling worker code - this avoids running things like html-webpack-plugin twice. For cases where it's necessary to apply a plugin to Worker code, use the plugins option.
Looking at the usage of WorkerPlugin deep within #angular-devkit we see the following:
#angular-devkit/src/angular-cli-files/models/webpack-configs/worker.js (simplified)
new WorkerPlugin({
globalObject: false,
plugins: [
getTypescriptWorkerPlugin(wco, workerTsConfigPath)
],
})
As we can see it uses the plugins option, but only for a single plugin which is responsible for the TypeScript compilation. This way the default plugins, configured by Webpack, including NodeTargetPlugin get lost and are not used for the worker.
Solution
To fix this we have to modify the Webpack config. And to do that we'll use #angular-builders/custom-webpack. Go ahead and install that package.
Next, open angular.json and update projects > angular-electron > architect > build:
"build": {
"builder": "#angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./extra-webpack.config.js"
}
// existing options
}
}
Repeat the same for serve.
Now, create extra-webpack.config.js in the same directory as angular.json:
const WorkerPlugin = require('worker-plugin');
const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
module.exports = (config, options) => {
let workerPlugin = config.plugins.find(p => p instanceof WorkerPlugin);
if (workerPlugin) {
workerPlugin.options.plugins.push(new NodeTargetPlugin());
}
return config;
};
The file exports a function which will be called by #angular-builders/custom-webpack with the existing Webpack config object. We can then search all plugins for an instance of the WorkerPlugin and patch its options adding the NodeTargetPlugin.

Jest test doesn't create the files the normal program would

I'm using node and puppeteer to load a page, get its content and then create a screenshot if it. At the end of the run function I have the following lines
var content = fs.writeFileSync(outputFilePath, processedContent);
var screenshot = page.screenshot({path: '../output/whatever.png', fullPage:true})
browser.close();
This works when running the node app. For testing I am using JEST
And when trying to run the JEST test that checks for the screenshot:
it('Run should take a screenshot', async() => {
const runResult = await run();
const screenshot = fs.readFileSync('/app/output/whatever.png');
expect(screenshot).toBeTruthy();
})
I get the following error ENOENT: no such file or directory, open '/app/output/whatever.png'
I'm having a hard time understanding why in the normal app flow the program creates the files when running but in the tests it doesn't. As additional info the entire thing runs in a Docker container
It is most likely because you are using an absolute path instead of a relative path in your jest test.
So instead of
const screenshot = fs.readFileSync('/app/output/whatever.png');
write
const screenshot = fs.readFileSync('./app/output/whatever.png');
to use a relative path
Also keep in mind your relative path should be from the the project root

Firebase -Node.js auto complete doesn't show .auth() or it's accompanying methods

I'm running Node version 7.8.0
I have installed the Firebase and Firebase-admin modules into a Server side Node.js app.js file. I want to use these 2 methods:
var myCustomToken = '12345'
firebaseAdmin.auth().createCustomToken(myCustomToken) //firebaseAdmin.auth()
firebase.auth().authenticateWithCustomToken(myCustomToken) // firebase.auth()
The problem is dot .auth() doesn't show up for either module so I can't get to use the 2 methods. There are other methods that are tied to both modules that appear (in pics below) but .auth() isn't one of them.
For e.g.
firebaseAdmin.initializeApp(... //works
firebaseAdmin.credential.cert(... //works
firebase.initializeApp(...) //works
These are the modules I installed in the folder that was initialized with npm:
npm install firebase-admin --save
npm install algoliasearch --save
npm install firebase --save
These are the dependencies inside my package.json file:
"engines": {
"node": "7.8.0"
},
"dependencies": {
"algoliasearch": "^3.22.1",
"firebase": "^3.7.4",
"firebase-admin": "^4.1.4"
}
How can I get .auth() to appear on each module so I can access the 2 methods I need?
Firebase-admin module autocomplete:
Firebase module autocomplete:
Autocomplete results for both modules .auth() doesn't exist:
Have a look at https://firebase.google.com/docs/admin/setup
and https://firebase.google.com/docs/auth/admin/create-custom-tokens#create_custom_tokens_using_the_firebase_admin_sdk
for createCustomToken()
As for the client part, did you try signInWithCustomToken() ?
I filed an issue report at the Firebase-admin github repo and they got back to me and said that even though the .aut() object isn’t showing up in Sublime’s autocomplete it does exist. Since I knew the methods I was looking they said I could just manually put in the code and it would work which in fact it did.
One thing they suggested was that next time I can go into the node_modules folder and I would see that it does exist there:
node_modules/firebase-admin/lib/firebase-namespace.js
this is what is there:
Object.defineProperty(FirebaseNamespace.prototype, "auth", {
/**
* Gets the `Auth` service namespace. The returned namespace can be used to get the
* `Auth` service for the default app or an explicitly specified app.
*/
get: function () {
var _this = this;
var fn = function (app) {
return _this.ensureApp(app).auth();
};
return Object.assign(fn, { Auth: auth_1.Auth });
},
enumerable: true,
configurable: true
});
Basically if your using Sublime and autocomplete isn’t showing what your looking for just manually type it in and look through the node_modules folder to verify it’s there.
Another alternative is to use VSCode or Vim instead of Sublime and the autocomplete should work there.

Resources