Promisify mkdir on a recursive directory - node.js

I've promisified fs.mkdir(). When I try to create a single directory in /tmp, it works, but tI receive a ENOENT error when I try to create a nested directory, even though I sent in the { recursive: true } option.
const mkdirAsync = util.promisify(fs.mkdir);
...
const ensureDir = ({ logger, createError }, event) => mkdirAsync(`/tmp/${event.mediaAssetUuid}/variants`, { recursive: true }).catch((err) => {
if (err.code !== 'EEXIST') {
const err2 = createError(
err,
{ logger },
`Internal Server Error. Error generating image variant for file: ${event.mediaAssetUuid}`,
null,
);
throw err2;
}
});
Error:
{
"jse_shortmsg": "Internal Server Error. Error generating image variant for file: 83ec01d8-8978-4eb0-9b0b-304f1e65cb14",
"jse_cause": {
"errno": -2,
"code": "ENOENT",
"syscall": "mkdir",
"path": "/tmp/83ec01d8-8978-4eb0-9b0b-304f1e65cb14/variants"
},

Node version 10 is required to use the recursive option.

Related

Nestjs throw error and http status 400 when fileFilter in fileinterceptor finds an unsupported file extension

I am having difficulty handling an error in my application.
I want to create a FileInterceptor (multer) which checks if the file has an allowed file extension. The documentation shows this:
const allowedFileExtensions = ['.jpg', '.png'];
FileInterceptor(
'image',
{
dest: './uploads',
fileFilter: (req, file, callback) => {
const extension = path.extname(file.originalname);
if (allowedFileExtensions.includes(extension)) {
callback(null, true);
} else {
// gives the 500 error
callback(new Error('Only images are allowed'), false);
}
}
}
This kinda works. But it has two flaws in my opinion. First, it returns a 500 error:
{
"statusCode": 500,
"message": "Internal server error"
}
It would be better to return a 400 error with a error message which explains why it failed.
Second, in the console of the Nest application it shows the stacktrace. I'd rather use the logging for this instead. (The application has middleware in place to pick up NestJS errors and log them automagically.)
So what I am trying is the following:
const allowedFileExtensions = ['.jpg', '.png'];
FileInterceptor(
'image',
{
dest: './uploads',
fileFilter: (req, file, callback) => {
const extension = path.extname(file.originalname);
if (!allowedFileExtensions.includes(extension)) {
// crashes the application
throw new BadRequestException('Only images are allowed', `Bad request. Accepted file extensions are: ${allowedFileExtensions.toString()}`);
}
callback(null, true)
}
}
But this crashes the application. I am not able to upload a different image anymore after this.
Any idea?
Ah found it. The BadRequestException cannot be thrown outside the body of the function.
const allowedFileExtensions = ['.jpg', '.png'];
enum FileValidationErrors {
UNSUPPORTED_FILE_TYPE
}
#Post('/:id/upload-photo')
#UseInterceptors(
FileInterceptor(
'image',
{
dest: './uploads',
fileFilter: (req, file, callback) => {
const extension = path.extname(file.originalname);
if (allowedFileExtensions.includes(extension)) {
callback(null, true);
} else {
// provide the validation error in the request
req.fileValidationError = FileValidationErrors.UNSUPPORTED_FILE_TYPE
callback(null, false);
}
}
}
)
)
uploadSinglePhoto(
#Param('id', ParseIntPipe) id: number,
#UploadedFile() image,
#Req() req // add the request property
): Promise<UserProfileEntity> {
// check here for a potential error
if (req?.fileValidationError === FileValidationErrors.UNSUPPORTED_FILE_TYPE) {
// if so, throw the BadRequestException
throw new BadRequestException('Only images are allowed', `Bad request. Accepted file extensions are: ${allowedFileExtensions.toString()}`);
}
this.logger.verbose(`Adding image ${image}`);
const imageUrlLocation = `${image.destination.substring(1)}/${image.filename}`;
return this.userProfileService.saveUserProfilePhotoLocation(id, imageUrlLocation);
}

next-translate Cannot find module './locales/en/common.json'

I am trying to integrate the next-translate library into my Next app, however I am getting an error when configuring the loadLocaleFrom function
This is what my i18n.js file looks like:
module.exports = {
locales: ["en", "fr", "es", "ru", "ar", "zh", "hi", "sw"],
defaultLocale: "en",
pages: {
"*": ["common"],
"/": ["home"],
},
loadLocaleFrom: async (lang, ns) => {
try {
const m = await import(`./locales/${lang}/${ns}.json`);
return {
...m.default,
};
} catch (error) {
console.log(error);
}
},
};
And my next.config file:
const withPlugins = require("next-compose-plugins");
const withImages = require("next-images");
const nextTranslate = require("next-translate");
module.exports = withPlugins([withImages, nextTranslate], {
reactStrictMode: true,
images: {
disableStaticImages: true,
},
});
package.json version:
next-translate: ^1.5.0
next: 12.1.6
react: 17.0.2
Even though my directory has both, the common.json and the home.json files in the correct folder structure, the loadLocaleFrom function still throws an error that looks like this:
Error: Cannot find module './locales/en/common.json'
at webpackEmptyContext (D:\projects\mk\mk-academy\.next\server\pages\index.js:529:10)
at eval (webpack-internal:///./i18n.js:64:89)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Object.loadLocaleFrom (webpack-internal:///./i18n.js:63:23)
at async Promise.all (index 0) {
code: 'MODULE_NOT_FOUND'
}
I did try using the appWithI18n hoc in _app.js but that doesn't solve it too. I also did try moving the locales to a different directory under src but that shouldn't make a difference.
The image shows my directory structure
require worked for me instead of import
await require(`./locales/${lang}/${ns}.json`)

Try and catch CATCH ERROR: ERROR STATUS: 403 (What the error is due to?)

I'm trying to deploy a smart contract, but before doing so I'm accessing${basePath}/build/ipfsMetasGeneric/_ipfsMetasResponse.json and picking up the metaData.metadata_uri to assign it to PREREVEAL_TOKEN_URI. It all works well until there (I can see on the terminal the console.log (PREREVEAL_TOKEN_URI)). But the app stop working right after as it catches an error and throws me the message CATCH ERROR: ERROR STATUS: 403.
I'm just quite puzzled since I don't understand why the try code runs all Ok but then throws me that error. I've hit a roadblock, would appreciate any help.
Thank you.
Code follows:
const path = require("path");
const basePath = process.cwd();
const fs = require("fs");
const yesno = require('yesno');
const {
fetchNoRetry,
} = require(`${basePath}/utils/functions/fetchWithRetry.js`);
let {
CHAIN,
GENERIC,
CONTRACT_NAME,
CONTRACT_SYMBOL,
METADATA_UPDATABLE,
ROYALTY_SHARE,
ROYALTY_ADDRESS,
MAX_SUPPLY,
MINT_PRICE,
TOKENS_PER_MINT,
OWNER_ADDRESS,
TREASURY_ADDRESS,
PUBLIC_MINT_START_DATE,
BASE_URI,
PREREVEAL_TOKEN_URI,
PRESALE_MINT_START_DATE,
PRESALE_WHITELISTED_ADDRESSES
} = require(`${basePath}/src/config.js`);
const deployContract = async () => {
const ok = await yesno({
question: `Is all REQUIRED contract information correct in config.js? (y/n):`,
default: null,
});
if(!ok) {
console.log("Exiting...");
process.exit(0);
}
if(GENERIC) {
try {
let jsonFile = fs.readFileSync(`${basePath}/build/ipfsMetasGeneric/_ipfsMetasResponse.json`);
let metaData = JSON.parse(jsonFile);
console.log (metaData);
if(metaData.response === "OK") {
if(!PREREVEAL_TOKEN_URI) {
PREREVEAL_TOKEN_URI = metaData.metadata_uri;
console.log (PREREVEAL_TOKEN_URI);
}
} else {
console.log('There is an issue with the metadata upload. Please check the /build/_ipfsMetasGeneric/_ipfsMetasResponse.json file for more information. Running "npm run upload_metadata" may fix this issue.');
}
} catch (err) {
console.log(`/build/_ipfsMetasGeneric/_ipfsMetasResponse.json file not found. Run "npm run upload_metadata" first.`);
console.log(`Catch: ${err}`);
process.exit(0);
}
} else {
try {
let jsonFile = fs.readFileSync(`${basePath}/build/ipfsMetas/_ipfsMetasResponse.json`);
let metaData = JSON.parse(jsonFile);
if(metaData.response === "OK") {
if(!BASE_URI) {
BASE_URI = metaData.metadata_directory_ipfs_uri;
}
} else {
console.log('There is an issue with the metadata upload. Please check the /build/_ipfsMetas/_ipfsMetasResponse.json file for more information. Running "npm run upload_metadata" may fix this issue.');
}
} catch (err) {
console.log(`/build/_ipfsMetasGeneric/_ipfsMetasResponse.json file not found. Run "npm run upload_metadata" first.`);
process.exit(0);
}
}
if (!fs.existsSync(path.join(`${basePath}/build`, "/contract"))) {
fs.mkdirSync(path.join(`${basePath}/build`, "contract"));
}
try {
const url = `https://api.nftport.xyz/v0/contracts/collections`;
const contract = {
chain: CHAIN.toLowerCase(),
name: CONTRACT_NAME,
symbol: CONTRACT_SYMBOL,
owner_address: OWNER_ADDRESS,
metadata_updatable: METADATA_UPDATABLE,
royalties_share: ROYALTY_SHARE,
royalties_address: ROYALTY_ADDRESS,
max_supply: MAX_SUPPLY,
mint_price: MINT_PRICE,
tokens_per_mint: TOKENS_PER_MINT,
treasury_address: TREASURY_ADDRESS,
public_mint_start_date: PUBLIC_MINT_START_DATE,
presale_mint_start_date: PRESALE_MINT_START_DATE,
base_uri: BASE_URI,
prereveal_token_uri: PREREVEAL_TOKEN_URI,
presale_whitelisted_addresses: PRESALE_WHITELISTED_ADDRESSES
};
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(contract),
};
const response = await fetchNoRetry(url, options);
fs.writeFileSync(`${basePath}/build/contract/_deployContractResponse.json`, JSON.stringify(response, null, 2));
if(response.response === "OK") {
console.log(`Contract deployment started.`);
} else {
console.log(`Contract deployment failed`);
}
console.log(`Check /build/contract/_deployContractResponse.json for more information. Run "npm run get_contract" to get the contract details.`);
} catch (error) {
console.log(`CATCH: Contract deployment failed`, `ERROR: ${error}`);
}
};
deployContract();

How can i get many details as possible about error using React Error boundry get error details?

Im tring to catch more details when error accuring.
when the error is accuring im using node api server to catch the error and save in log file.
i simulated a Network Error and tring to get many details as possible.
when i console.log the error in frontend im getting this:
withFormHandler.js:28 Uncaught Error: Error: Network Error
at Object.componentDidUpdate (withFormHandler.js:28)
...
but i cant send this information using my api.
all im getting in the server side is an empty object.
so how can i catch and send many details as possible about the error and write it to the log file?
this is my ErrorBoundry component:
class ErrorBoundary extends React.Component {
state = {
hasError: false,
error: { message: "", stack: "" },
info: { componentStack: "" },
};
static getDerivedStateFromError = (error) => {
return { hasError: true };
};
componentDidCatch = (error, info) => {
this.setState({ error, info });
axios
.get(`http://localhost:5001/api/logs/error`, {
params: {
error: error.message,
details: info,
// details:error ---> this is also not give me information i need
},
})
.catch(() => {});
};
render() {
const { hasError, error, info } = this.state;
const { children } = this.props;
return hasError ? <ErrorComponent message={error.message} /> : children;
}
}
this is the server side handle:
router.get("/error", (req, res) => {
const errorMessage = req.query.error;
const details = req.query.details; -----> return an empty object :(
const logFile = "./logs/debug.log";
if (errorMessage) {
let error = errorMessage + "\r\n" + details;
fs.appendFile(logFile, error, function (err) {
// callback or something
});
}
});

How to return grpc error in nodejs

I want to return grpc error code and description in server-side. I have tried this
function sayHello(call, callback) {
callback({error: {code: 400, message: "invalid input"});
}
but I got this exception from client
{ Error: Unknown Error
at /home/thanh/email/node_modules/grpc/src/node/src/client.js:434:17 code: 2, metadata: Metadata { _internal_repr: {} } }
If I don't want to include error field in message definition like this.
message Hello {
string name = 1;
string error = 2; // don't want this
}
Then what is the proper way to send grpc error back to client ?
Change it to:
return callback({
code: 400,
message: "invalid input",
status: grpc.status.INTERNAL
})
As a supplement, GRPC only allowed 16 kinds of error. You can check all error code from its site: https://grpc.io/docs/guides/error/#error-status-codes.
And here I found an example code for NodeJs error handling: https://github.com/avinassh/grpc-errors/blob/master/node/server.js
To clarify what #avi and #murgatroid99 have said what you want to do is structure you callback like so:
import * as grpc from '#grpc/grpc-js';
try{
somethingThatThrowsAnError();
}catch(e){
return callback(
{
message: e ,
code: grpc.status.NOT_FOUND
},
null,
)
}
grpc.status.NOT_FOUND is just a integer, 5, and when the client gets an error response from the server you can read it off the err prop returned e.g.
const client = new MyServiceConstructor(
address,
grpc.credentials.createInsecure()
);
client.myMethod(
myRequest,
metadata ?? new grpc.Metadata(),
(error: string, response: T_RESPONSE_TYPE) => {
if (error) {
if(error.code === grpc.status.NOT_FOUND) {
return handleNotFound(error, myRequest)
}
return unknownError(error, myRequest)
}
return response
},
);

Resources