Skip to content

Commit 9b9ed18

Browse files
committed
Fix legacy boom object support
1 parent 60893c0 commit 9b9ed18

File tree

3 files changed

+80
-38
lines changed

3 files changed

+80
-38
lines changed

lib/index.js

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,16 @@ exports.Boom = class Boom extends Error {
7676
return this.output.statusCode >= 500;
7777
}
7878

79+
set isServer(value) {} // Allow for compatiblity with legacy boom
80+
7981
constructor(message, options = {}) {
8082

8183
const { statusCode = 500, data, headers, ctor = exports.Boom } = options;
8284

8385
super(message ?? internals.codes.get(statusCode) ?? 'Unknown', options);
8486
Error.captureStackTrace(this, ctor); // Filter the stack to our external API
8587

86-
this.#apply(data, statusCode, headers);
88+
internals.apply(this, data, statusCode, headers);
8789
}
8890

8991
static [Symbol.hasInstance](instance) {
@@ -102,53 +104,58 @@ exports.Boom = class Boom extends Error {
102104
this.output.payload = new internals.PayloadObject(this, this.output.statusCode, debug);
103105
}
104106

105-
#apply(data, statusCode, headers, message) {
107+
static {
108+
Object.defineProperty(this.prototype, 'name', { value: 'Boom', writable: true, configurable: true });
109+
Object.defineProperty(this.prototype, 'isBoom', { value: true, writable: true, configurable: true });
110+
}
111+
};
106112

107-
if (data !== undefined) {
108-
this.data = data;
109-
}
110113

111-
if (statusCode) {
112-
const numberCode = parseInt(statusCode, 10);
113-
if (isNaN(numberCode) || numberCode < 400) {
114-
throw new TypeError(`statusCode must be a number (400+): ${statusCode}`);
115-
}
114+
exports.isBoom = function (err, statusCode) {
116115

117-
if (message) {
118-
this.message = `${message}: ${this.message}`;
119-
}
116+
return err instanceof Error && !!err.isBoom && (!statusCode || err.output.statusCode === statusCode);
117+
};
120118

121-
const payload = new internals.PayloadObject(this, numberCode, false);
122-
this.output = new internals.BoomOutput(numberCode, payload, headers);
123-
}
119+
120+
exports.boomify = function (err, options = {}) {
121+
122+
const { override, data, statusCode, message } = options;
123+
124+
if (!err?.isBoom) {
125+
return new exports.Boom(message, { statusCode, cause: err, data });
124126
}
125127

126-
static {
127-
Object.defineProperty(this.prototype, 'name', { value: 'Boom', writable: true, configurable: true });
128-
Object.defineProperty(this.prototype, 'isBoom', { value: true, configurable: true });
128+
if (override === false) { // Defaults to true
129+
internals.apply(err, data);
130+
}
131+
else {
132+
internals.apply(err, data, statusCode ?? err.output.statusCode, {}, message);
133+
}
129134

130-
exports.isBoom = function (err, statusCode) {
135+
err.isServer = err.output.statusCode >= 500; // Assign, in case it is a legacy boom object
131136

132-
return err instanceof Error && !!err.isBoom && (!statusCode || err.output.statusCode === statusCode);
133-
};
137+
return err;
138+
};
134139

135-
exports.boomify = function (err, options = {}) {
136140

137-
const { override, data, statusCode, message } = options;
141+
internals.apply = function (boom, data, statusCode, headers, message) {
138142

139-
if (!err?.isBoom) {
140-
return new exports.Boom(message, { statusCode, cause: err, data });
141-
}
143+
if (data !== undefined) {
144+
boom.data = data;
145+
}
142146

143-
if (override === false) { // Defaults to true
144-
err.#apply(data);
145-
}
146-
else {
147-
err.#apply(data, statusCode ?? err.output.statusCode, {}, message);
148-
}
147+
if (statusCode) {
148+
const numberCode = parseInt(statusCode, 10);
149+
if (isNaN(numberCode) || numberCode < 400) {
150+
throw new TypeError(`statusCode must be a number (400+): ${statusCode}`);
151+
}
149152

150-
return err;
151-
};
153+
if (message) {
154+
boom.message = `${message}: ${boom.message}`;
155+
}
156+
157+
const payload = new internals.PayloadObject(boom, numberCode, false);
158+
boom.output = new internals.BoomOutput(numberCode, payload, headers);
152159
}
153160
};
154161

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@
2525
"@hapi/eslint-plugin": "*",
2626
"@hapi/lab": "^25.1.0",
2727
"@types/node": "^17.0.31",
28-
"typescript": "~4.6.4"
28+
"typescript": "~4.6.4",
29+
"@hapi/boom10": "npm:@hapi/boom@^10.0.1"
2930
},
3031
"scripts": {
31-
"test": "lab -a @hapi/code -t 100 -L -Y",
32+
"test": "lab -a @hapi/code -t 100 -L",
3233
"test-cov-html": "lab -a @hapi/code -t 100 -L -r html -o coverage.html"
3334
},
3435
"license": "BSD-3-Clause"

test/index.js

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const Boom = require('..');
4+
const Boom10 = require('@hapi/boom10');
45
const Code = require('@hapi/code');
56
const Lab = require('@hapi/lab');
67

@@ -107,6 +108,7 @@ describe('Boom', () => {
107108
const BadaBoom = class extends Boom.Boom {};
108109

109110
expect(new Boom.Boom('oops')).to.be.instanceOf(Boom.Boom);
111+
expect(new Boom10.Boom('oops')).to.be.instanceOf(Boom.Boom);
110112
expect(new BadaBoom('oops')).to.be.instanceOf(Boom.Boom);
111113
expect(Boom.badRequest('oops')).to.be.instanceOf(Boom.Boom);
112114
expect(new Error('oops')).to.not.be.instanceOf(Boom.Boom);
@@ -128,6 +130,12 @@ describe('Boom', () => {
128130
expect(new Boom.Boom('oops')).to.not.be.instanceOf(BadaBoom);
129131
expect(Boom.badRequest('oops')).to.not.be.instanceOf(BadaBoom);
130132
});
133+
134+
it('works from legacy boom', () => {
135+
136+
expect(new Boom.Boom('oops')).to.be.instanceOf(Boom10.Boom);
137+
expect(new Boom10.Boom('oops')).to.be.instanceOf(Boom10.Boom);
138+
});
131139
});
132140

133141
describe('isBoom()', () => {
@@ -137,6 +145,7 @@ describe('Boom', () => {
137145
// Success
138146

139147
expect(Boom.isBoom(new Boom.Boom('oops'))).to.be.true();
148+
expect(Boom.isBoom(new Boom10.Boom('oops'))).to.be.true();
140149

141150
// Fail
142151

@@ -148,11 +157,19 @@ describe('Boom', () => {
148157
it('returns true for valid boom object and valid status code', () => {
149158

150159
expect(Boom.isBoom(Boom.notFound(),404)).to.be.true();
160+
expect(Boom.isBoom(Boom10.notFound(), 404)).to.be.true();
151161
});
152162

153163
it('returns false for valid boom object and wrong status code', () => {
154164

155-
expect(Boom.isBoom(Boom.notFound(),503)).to.be.false();
165+
expect(Boom.isBoom(Boom.notFound(), 503)).to.be.false();
166+
expect(Boom.isBoom(Boom10.notFound(), 503)).to.be.false();
167+
});
168+
169+
it('works from legacy boom', () => {
170+
171+
expect(Boom10.isBoom(new Boom.Boom('oops'))).to.be.true();
172+
expect(Boom10.isBoom(new Boom10.Boom('oops'))).to.be.true();
156173
});
157174
});
158175

@@ -272,6 +289,23 @@ describe('Boom', () => {
272289
expect(boom.output.payload.message).to.equal('Hello: 123');
273290
expect(boom.output.statusCode).to.equal(400);
274291
});
292+
293+
it('works with legacy boom', () => {
294+
295+
const boom = Boom.boomify(new Boom10.Boom(null, { statusCode: 404 }), { statusCode: 501, message: 'Override' });
296+
297+
expect(boom.cause).to.be.undefined();
298+
expect(boom.message).to.equal('Override: Not Found');
299+
expect(boom.isServer).to.be.true();
300+
expect(boom.output.statusCode).to.equal(501);
301+
302+
const boom10 = Boom10.boomify(new Boom.Boom(null, { statusCode: 404 }), { statusCode: 501, message: 'Override' });
303+
304+
expect(boom10.cause).to.be.undefined();
305+
expect(boom10.message).to.equal('Override: Not Found');
306+
expect(boom10.isServer).to.be.true();
307+
expect(boom10.output.statusCode).to.equal(501);
308+
});
275309
});
276310

277311
describe('create()', () => {

0 commit comments

Comments
 (0)