diff --git a/CHANGES.md b/CHANGES.md index 8c599f3f..9a21434f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,15 @@ +2014-12-12, Version 2.8.5 +========================= + + * fix jshint errors (Clark Wang) + + * test if cb exists (Clark Wang) + + * fix nested remoting function throwing error will crash app (Clark Wang) + + * Fix bcrypt issues for browserify (Raymond Feng) + + 2014-12-08, Version 2.8.4 ========================= @@ -1228,14 +1240,6 @@ * 2.0.0-beta1 (Ritchie Martori) - * Bump version (Raymond Feng) - - * Add postgresql to the keywords (Raymond Feng) - - * updated package.json with SOAP and framework keywords (altsang) - - * updated package.json with keywords and updated description (Raymond Feng) - * Make app.datasources unique per app instance (Miroslav Bajtoš) * Add RC version (Ritchie Martori) @@ -1301,11 +1305,6 @@ * Add Change model (Ritchie Martori) -2014-05-27, Version 1.8.4 -========================= - - - 2014-05-27, Version 1.8.5 ========================= @@ -1317,8 +1316,14 @@ * updated package.json with keywords and updated description (Raymond Feng) + +2014-05-27, Version 1.8.4 +========================= + * Add more keywords (Raymond Feng) + * Bump version (Raymond Feng) + * app: flatten model config (Miroslav Bajtoš) * Fix the test for mocha 1.19.0 (Raymond Feng) diff --git a/Gruntfile.js b/Gruntfile.js index fd48c0eb..55c18b17 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -70,7 +70,7 @@ module.exports = function(grunt) { 'dist/loopback.js': ['index.js'], }, options: { - ignore: ['nodemailer', 'passport'], + ignore: ['nodemailer', 'passport', 'bcrypt'], standalone: 'loopback' } } @@ -174,7 +174,8 @@ module.exports = function(grunt) { 'passport', 'passport-local', 'superagent', - 'supertest' + 'supertest', + 'bcrypt' ], // transform: ['coffeeify'], // debug: true, diff --git a/common/models/user.js b/common/models/user.js index 563d0363..e9fee16e 100644 --- a/common/models/user.js +++ b/common/models/user.js @@ -11,6 +11,10 @@ var bcrypt; try { // Try the native module first bcrypt = require('bcrypt'); + // Browserify returns an empty object + if (bcrypt && typeof bcrypt.compare !== 'function') { + bcrypt = require('bcryptjs'); + } } catch (err) { // Fall back to pure JS impl bcrypt = require('bcryptjs'); diff --git a/lib/model.js b/lib/model.js index 8b55c5d4..d93e4ab4 100644 --- a/lib/model.js +++ b/lib/model.js @@ -674,7 +674,11 @@ Model.nestRemoting = function(relationName, options, cb) { this[getterName](fkId, function(err, inst) { if (err && cb) return cb(err); if (inst instanceof relation.modelTo) { - nestedFn.apply(inst, args); + try { + nestedFn.apply(inst, args); + } catch (err) { + if (cb) return cb(err); + } } else if (cb) { cb(err, null); } @@ -688,7 +692,11 @@ Model.nestRemoting = function(relationName, options, cb) { this[getterName](function(err, inst) { if (err && cb) return cb(err); if (inst instanceof relation.modelTo) { - nestedFn.apply(inst, args); + try { + nestedFn.apply(inst, args); + } catch (err) { + if (cb) return cb(err); + } } else if (cb) { cb(err, null); } diff --git a/package.json b/package.json index dd35db58..1b70b9fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loopback", - "version": "2.8.4", + "version": "2.8.5", "description": "LoopBack: Open Source Framework for Node.js", "homepage": "http://loopback.io", "keywords": [ @@ -94,7 +94,8 @@ "express": "./lib/browser-express.js", "./lib/server-app.js": "./lib/browser-express.js", "connect": false, - "nodemailer": false + "nodemailer": false, + "bcrypt": false }, "license": { "name": "Dual MIT/StrongLoop", diff --git a/test/relations.integration.js b/test/relations.integration.js index 4ba459f2..f1aa72da 100644 --- a/test/relations.integration.js +++ b/test/relations.integration.js @@ -1168,6 +1168,13 @@ describe('relations - integration', function() { Page.hasMany(Note); Image.belongsTo(Book); + // fake a remote method that match the filter in Model.nestRemoting() + Page.prototype['__throw__errors'] = function() { + throw new Error('This should not crash the app'); + }; + + Page.remoteMethod('__throw__errors', { isStatic: false, http: { path: '/throws', verb: 'get' } }); + Book.nestRemoting('pages'); Image.nestRemoting('book'); @@ -1305,6 +1312,19 @@ describe('relations - integration', function() { }); }); }); + + it('should catch error if nested function throws', function(done) { + var test = this; + this.get('/api/books/' + test.book.id + '/pages/' + this.page.id + '/throws') + .end(function(err, res) { + expect(res.body).to.be.an('object'); + expect(res.body.error).to.be.an('object'); + expect(res.body.error.name).to.equal('Error'); + expect(res.body.error.status).to.equal(500); + expect(res.body.error.message).to.equal('This should not crash the app'); + done(); + }); + }); }); });