Error after upgrading Joi to latest version - Schema can only contain plain objects (name) - node.js

After upgrading Joi to the latest version #hapi/Joi(17.1.1) my server is not staring I am getting below error on startup. Seems there were some breaking changes in recent versions. Not able to get any clue yet, any help is appreciated.
Error: Schema can only contain plain objects (name)
at new module.exports (/Users/xyz/project/projectxyz/node_modules/#hapi/hoek/lib/error.js:23:19)
at module.exports (/Users/xyz/project/projectxyz/node_modules/#hapi/hoek/lib/assert.js:20:11)
at Object.internals.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:88:5)
at Object.exports.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:17:26)
at internals.Base.$_compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/base.js:631:24)
at /Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/types/keys.js:255:92
at Object.exports.tryWithPath (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/common.js:173:16)
at internals.Base.method [as keys] (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/types/keys.js:255:32)
at Object.internals.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:90:25)
at Object.exports.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:17:26)
at Object.exports.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:117:24)
at Object.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/index.js:123:24)
at Object.exports.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/validation.js:49:22)
at module.exports.internals.Route._setupValidation (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/route.js:197:43)
at new module.exports.internals.Route (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/route.js:122:14)
at internals.Server._addRoute (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/server.js:498:23)
at internals.Server.route (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/server.js:491:22)
at /Users/xyz/project/projectxyz/src/app.js:73:14
at Array.forEach (<anonymous>)
at init (/Users/xyz/project/projectxyz/src/app.js:72:17)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at process.runNextTicks [as _tickCallback] (internal/process/task_queues.js:66:3) {
path: 'name'
} Server Init error Error: Schema can only contain plain objects (name)
at new module.exports (/Users/xyz/project/projectxyz/node_modules/#hapi/hoek/lib/error.js:23:19)
at module.exports (/Users/xyz/project/projectxyz/node_modules/#hapi/hoek/lib/assert.js:20:11)
at Object.internals.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:88:5)
at Object.exports.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:17:26)
at internals.Base.$_compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/base.js:631:24)
at /Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/types/keys.js:255:92
at Object.exports.tryWithPath (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/common.js:173:16)
at internals.Base.method [as keys] (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/types/keys.js:255:32)
at Object.internals.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:90:25)
at Object.exports.schema (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:17:26)
at Object.exports.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/compile.js:117:24)
at Object.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/joi/lib/index.js:123:24)
at Object.exports.compile (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/validation.js:49:22)
at module.exports.internals.Route._setupValidation (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/route.js:197:43)
at new module.exports.internals.Route (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/route.js:122:14)
at internals.Server._addRoute (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/server.js:498:23)
at internals.Server.route (/Users/xyz/project/projectxyz/node_modules/#hapi/hapi/lib/server.js:491:22)
at /Users/xyz/project/projectxyz/src/app.js:73:14
at Array.forEach (<anonymous>)
at init (/Users/xyz/project/projectxyz/src/app.js:72:17)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at process.runNextTicks [as _tickCallback] (internal/process/task_queues.js:66:3) {
path: 'name'
}

To anyone who finds themselves in this dark place again, for me it was an issue when extending a Joi schema using the spread operator:
joi.object().keys({
...otherSchema,
position: joi.number()
})
This was causing the "Schema can only contain plain objects" error when I upgraded to Joi 17.5.0. Using the keys() syntax got around it:
otherSchema.keys({
position: joi.number()
})

Thanks all for your comments. I was able to resolve it after going through Joi's release notes.
The problem was due to the mix of Joi versions. In my codebase older version of Joi was used which was causing this. Below Github issue helped me realizing the issue.
https://github.com/hapijs/joi/issues/1913

i think u should do some thing like this to handle this error:
var ObjectJoi = Joi.object({
//some item that you want to add
})
var mySchema = new Schema(Joigoose.convert(ObjectJoi))
const myModel = mongoose.model('myModel', mySchema);

It's hard to tell without seeing the code.
But I faced the same issue when using Joi.extend().
const extendedType = Joi.extend(Joi => {
return {
type: 'myType', // <- PAY ATTENTION
base: Joi.array(),
messages: {
'stringArray:base': '...'
},
validate(value, helpers) {
...
},
coerce(value, helpers) {
...
}
}
});
The problem was that I used extendedType like below by mistake:
Joi.object({
someKey: extendedType,
...
});
instead of:
Joi.object({
someKey: extendedType.myType(),
...
});

Related

pdf-merger-js throws a TypeError and Fails

I have been using pdf-merger-js to merge PDF files for a while now. I have used it with PDF files I have generated from HTML files and with PDF files I did not create.
Then I started getting the error:
Uncaught TypeError: Cannot read property 'compressed' of undefined
and the merger would fail. I tried different versions of node with the same results. The version that has been working is node v12.19.1.
/* /path/to/project/mpdf.js */
const PDFMerger = require('pdf-merger-js');
const path = require('path');
(async () => {
try {
const pdfs = ['pdf1.pdf','pdf2.pdf','pdf3.pdf','pdf4.pdf','pdf5.pdf'];
const merger = new PDFMerger();
pdfs.map(f => path.resolve(__dirname, "subfolder", f)
.forEach(pdf => merger.add(pdf));
//^^^Error occurs on this line
await merger.save('all-merged.pdf');
} catch( err ) {
console.log( err );
}
})();
Has any of you worked with pdf-merger-js and, have you encountered the above error? If so, how did you resolve the error?
Stack Trace
TypeError: Cannot read property 'compressed' of undefined
at parseObject (/path/to/project/node_modules/pdfjs/lib/object/reference.js:81:15)
at PDFReference.get [as object] (/path/to/project/node_modules/pdfjs/lib/object/reference.js:15:17)
at new ExternalDocument (/path/to/project/node_modules/pdfjs/lib/external.js:20:42)
at PDFMerger._addEntireDocument (/path/to/project/node_modules/pdf-merger-js/index.js:29:15)
at PDFMerger.add (/path/to/project/node_modules/pdf-merger-js/index.js:11:12)
at /path/to/project/app3.js:10:34
at Array.forEach (<anonymous>)
at /path/to/project/app3.js:10:12
at processTicksAndRejections (internal/process/task_queues.js:97:5)
Update
I have encountered another set of PDF files that are throwing a different error on the same line:
TypeError: Cannot read property 'object' of undefined
at new ExternalDocument (/path/to/project/node_modules/pdfjs/lib/external.js:20:42)
at PDFMerger._addEntireDocument (/path/to/project/node_modules/pdf-merger-js/index.js:29:15)
at PDFMerger.add (/path/to/project/node_modules/pdf-merger-js/index.js:11:12)
at /path/to/project/app3.js:10:34
at Array.forEach (<anonymous>)
at /path/to/project/app3.js:10:12
at processTicksAndRejections (internal/process/task_queues.js:97:5)
I got the same error whenever I used compressed PDFs for merging. Seems to be a bug in the underlying pdfjs library according to a Github issue in the pdf-merger-js repository.
Not the kind of answer I was looking for ....
If you flatten the files prior to merging them then the merging works fine. This seems to resolve the two errors I encountered.
I am using pdf-flatten just before merging as follows:
const fsp = require('fs').promises;
const flattener = require('pdf-flatten');
//....
const pdfs = ['pdf1.pdf','pdf2.pdf','pdf3.pdf','pdf4.pdf','pdf5.pdf'];
for(pdf of pdfs) {
const pdfB = await fsp.readFile(path.resolve(__dirname,"subfolder", pdf));
const pdfFlat = await flattener.flatten(pdfB, {density: 300});
await fsp.writeFile(path.resolve(__dirname,"subfolder", `flattened_${pdf}`), pdfFlat);
}
//....merge the flattened files:
//.... pdfs.map(p => `flattened_${p}`).....

mocking Phaser with Jest

I've been trying to set up jest as a test framework for a project I'm working on that uses Phaser, and I am getting stuck trying to mock out Phaser itself. I first ran into this issue with the missing canvas, which I was able to resolve from the link. But now I am getting another error "Cannot read property 'postion' of undefined".
jest.config.js:
module.exports = {
verbose: true,
roots: ['./src'],
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
moduleNameMapper: {
'\\.(css|less|scss)$': 'identity-obj-proxy'
},
setupFiles: ['jest-canvas-mock']
}
__mocks__/phaser.js:
const phaser = jest.genMockFromModule('phaser');
module.exports = phaser;
error message:
TypeError: Cannot read property 'position' of undefined
1 |
> 2 | const phaser = jest.genMockFromModule('phaser');
| ^
3 |
4 | module.exports = phaser;
at Image.get [as x] (node_modules/phaser/src/physics/matter-js/components/Transform.js:36:30)
at Array.forEach (<anonymous>)
at Array.forEach (<anonymous>)
at Array.forEach (<anonymous>)
at Array.forEach (<anonymous>)
at Array.forEach (<anonymous>)
at Object.<anonymous> (src/__mocks__/phaser.js:2:21)
at Object.<anonymous> (src/main.ts:3:1)
at Object.<anonymous> (src/main.spec.ts:3:1)
I'm looking at that Transform file and its blowing up on a getter because this.body is undefined:
get: function ()
{
return this.body.position.x;
},
Has anyone else had this problem? I'm hoping I just have some configuration wrong.
I wanted to thank you for sharing your configuration to run Jest with Phaser 3.
Regarding your issue, it appears that the Phaser.Physics.Matter.Commponents.Trasnform component is not really compatible with the way jest.genMockFromModule() works.
You can hack it simply by creating a default value for the body property of the Transform instance in phaser/src/physics/matter-js/components/Trasnform.js:
var Transform = {
body: Body.create({}),
// ...
Although I don't know how it might affect the production code.
If you don't use the Matter.js physics engine in your game, maybe you could create a custom Phaser 3 build instead.

How to remove TypeError: "x" is not a function?

I am trying to learn how to make a discord bot and pull data from this API called Ergast (http://ergast.com/mrd). I found this npm (https://github.com/estevE11/f1-stats) which uses NodeJS implementation to get a historical record of F1 data from Ergast API. Sorry for the bad wording I am still trying to learn the lingo.
I followed what was stated in the npm documentation for installing it and tried using the example to get data from the API. However when I run the code in index.js I get the error "TypeError: "x" is not a function". When I go into the node_modules "f1-stats" folder and run the code from main.js I do get the correct result.
index.js:
const client = new Discord.Client(); //This will be our client
const { prefix, token } = require('./config.json');//const PREFIX = '!';
const f1s = require('f1-stats');
//module.exports.f1s = f1s; //Still causes the TypeError
f1s("2008 drivers", (res) => {
console.log(res);
});
The error message I get in index.js:
f1s("2008 drivers", (res) => {
^
TypeError: f1s is not a function
at Object.<anonymous> (C:\Users\RyanPC\Documents\DiscordBot\index.js:8:1)
at Module._compile (internal/modules/cjs/loader.js:776:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
node_modules/f1-stats/main.js:
const f1s = require("./f1-stats"); // "./" is used because module is located in the same folder as the Node.js file
f1s("2008 drivers", (res) => {
console.log(res);
});
when I run it in node_modules/f1-stats/main.js:
{ MRData:
{ xmlns: 'http://ergast.com/mrd/1.4',
series: 'f1',
url: 'http://ergast.com/api/f1/2008/drivers.json',
limit: '30',
offset: '0',
total: '22',
DriverTable: { season: '2008', Drivers: [Array] } } }
Because f1-stats doesn't export anything so when you import it. It is empty. The correct file you need to import is f1-stats/f1-stats.
const f1s = require('f1-stats/f1-stats');
try importing f1s properly , you are getting error because you have not imported the function properly , in other words...check what is being exported from what are you trying to import....hope it solves the problem.

Type Error: Cannot read property 'hasListCollectionsCommand' of null

I'm trying to get all collection names in mongodb (v4.0.2) and using mongodb#3.1.10 nodejs driver. From the docs, I can see that listCollections might work, but running the following:
const Db = require('mongodb').Db
const Server = require('mongodb').Server
const db = new Db(dbName, new Server(host, port, options), {})
db.listCollections().toArray((error, collectionNames) => {
console.error(error)
console.log(JSON.stringify(collectionNames))
})
… leads to this error:
if (this.serverConfig.capabilities().hasListCollectionsCommand) {
TypeError: Cannot read property 'hasListCollectionsCommand' of null
at Db.listCollections ({path}/node_modules/mongodb/lib/db.js:493:39)
at db.createCollection ({path}/sampleMongoDB.js:19:8)
at err ({path}/node_modules/mongodb/lib/utils.js:415:14)
at executeCallback ({path}/node_modules/mongodb/lib/utils.js:404:25)
at executeOperation ({path}/node_modules/mongodb/lib/utils.js:422:7)
at Db. ({path}/node_modules/mongodb/lib/db.js:431:12)
at Db.deprecated [as createCollection] ({path}/node_modules/mongodb /lib/utils.js:661:17)
at Object.< anonymous > ({path}/sampleMongoDB.js:18:6)
at Module._compile (module.js:653:30)
at Object.Module._extensions..js (module.js:664:10)
My questions are:
Is there a docs site for MongoDB NodeJs drivers where we can refer examples from?
If not, what's the correct way to query?
I was able to work it out. The MongoClient's instance returns a db instance, which inturn helps run mongodb.Db methods.
Here's a sample code that worked (Ref. to MongoDB guides)
const options = {
useNewUrlParser: true, // Add this, if you wish to avoid {https://stackoverflow.com/questions/50448272/avoid-current-url-string-parser-is-deprecated-warning-by-setting-usenewurlpars} issue
}
const client = new MongoClient(connectionUri, options)
return client.connect().then(() => {
const db = client.db(dbName)
return db.listCollections()
.toArray()
.then((collections) => {
// Collections array
})
})
#Community mods - if required, kindly close this question.

GQL queries not working using gcloud (google-cloud) and node.js

I am trying to run the following GQL query:
function gqlExample(callback) {
datastore.runQuery({
gqlQuery: {
queryString: 'SELECT * FROM Person',
}
}).execute(function(err, result) {
if (!err) {
// Iterate over the results and return the entities.
result = (result.batch.entityResults || []).map(
function(entityResult) {
return entityResult.entity;
});
}
callback(err, result);
});
}
I found the above example on the following page:
http://ec2-54-66-129-240.ap-southeast-2.compute.amazonaws.com/httrack/docs/cloud.google.com/datastore/docs/concepts/gql.html
It states that it is a valid node.js example but on running the query I get the following error:
/Users/xxxx/relay-fullstack/server/data/campaign-datastore.js:245
}).execute(function (err, result) {
^
TypeError: ds.runQuery(...).execute is not a function
at Object.campaignSearchGql (campaign-datastore.js:265:6)
at Test.<anonymous> (datastore-test.js:29:16)
at Test.bound [as _cb] (/Users/xxxx/relay-fullstack/node_modules/tape/lib/test.js:63:32)
at Test.run (/Users/xxxx/relay-fullstack/node_modules/tape/lib/test.js:82:10)
at Test.bound [as run] (/Users/xxxx/relay-fullstack/node_modules/tape/lib/test.js:63:32)
at Immediate.next [as _onImmediate] (/Users/xxxx/relay-fullstack/node_modules/tape/lib/results.js:70:15)
at tryOnImmediate (timers.js:534:15)
at processImmediate [as _immediateCallback] (timers.js:514:5)
I am using the latest version of google cloud for node:
"google-cloud": "^0.38.3",
Has anyone got GQL queries executing correctly with gcloud and node? Any help will be greatly appreciated.
That is apparently a cached version of the Datastore docs. Those Node.js snippets are using a different library called googleapis: https://github.com/google/google-api-nodejs-client
The other library, gcloud-node, doesn't support GQL at this time.

Resources