You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@fastify/error

Package Overview
Dependencies
Maintainers
20
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fastify/error - npm Package Compare versions

Comparing version
4.1.0
to
4.2.0
+263
test/instanceof.test.js
'use strict'
const cp = require('node:child_process')
const fs = require('node:fs')
const path = require('node:path')
const os = require('node:os')
const test = require('node:test')
const { createError, FastifyError } = require('..')
test('Readme: All errors created with `createError` will be instances of the base error constructor you provided, or `Error` if none was provided.', (t) => {
t.plan(3)
const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError)
const customError = new CustomError('world')
t.assert.ok(customError instanceof CustomError)
t.assert.ok(customError instanceof TypeError)
t.assert.ok(customError instanceof Error)
})
test('Readme: All instantiated errors will be instances of the `FastifyError` class. The `FastifyError` class can be required from the module directly.', (t) => {
t.plan(1)
const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError)
const customError = new CustomError('world')
t.assert.ok(customError instanceof FastifyError)
})
test('Readme: It is possible to create a `FastifyError` that extends another `FastifyError`, created by `createError`, while instanceof working correctly.', (t) => {
t.plan(5)
const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError)
const ChildCustomError = createError('CHILD_ERROR_CODE', 'Hello %s', 500, CustomError)
const customError = new ChildCustomError('world')
t.assert.ok(customError instanceof ChildCustomError)
t.assert.ok(customError instanceof CustomError)
t.assert.ok(customError instanceof FastifyError)
t.assert.ok(customError instanceof TypeError)
t.assert.ok(customError instanceof Error)
})
test('Readme: Changing the code of an instantiated Error will not change the result of the `instanceof` operator.', (t) => {
t.plan(3)
const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError)
const AnotherCustomError = createError('ANOTHER_ERROR_CODE', 'Hello %s', 500, CustomError)
const customError = new CustomError('world')
customError.code = 'ANOTHER_ERROR_CODE'
t.assert.ok(customError instanceof CustomError)
t.assert.ok(customError instanceof AnotherCustomError === false)
t.assert.ok(customError instanceof FastifyError)
})
test('check if createError creates an Error which is instanceof Error', (t) => {
t.plan(3)
const CustomFastifyError = createError('CODE', 'Not available')
const err = CustomFastifyError()
t.assert.ok(err instanceof Error)
t.assert.ok(err instanceof SyntaxError === false)
t.assert.ok(err instanceof TypeError === false)
})
test('check if createError creates an Error which is instanceof FastifyError', (t) => {
t.plan(4)
const CustomFastifyError = createError('CODE', 'Not available')
const err = CustomFastifyError()
t.assert.ok(err instanceof Error)
t.assert.ok(err instanceof FastifyError)
t.assert.ok(err instanceof SyntaxError === false)
t.assert.ok(err instanceof TypeError === false)
})
test('check if createError creates an Error with the right BaseConstructor', (t) => {
t.plan(2)
const CustomFastifyError = createError('CODE', 'Not available', 500, TypeError)
const err = CustomFastifyError()
t.assert.ok(err instanceof Error)
t.assert.ok(err instanceof TypeError)
})
test('check if createError creates an Error with the right BaseConstructor, which is a FastifyError', (t) => {
t.plan(6)
const BaseFastifyError = createError('CODE', 'Not available', 500, TypeError)
const CustomFastifyError = createError('CODE', 'Not available', 500, BaseFastifyError)
const err = CustomFastifyError()
t.assert.ok(err instanceof Error)
t.assert.ok(err instanceof TypeError)
t.assert.ok(err instanceof FastifyError)
t.assert.ok(err instanceof BaseFastifyError)
t.assert.ok(err instanceof CustomFastifyError)
t.assert.ok(err instanceof SyntaxError === false)
})
// for more information see https://github.com/fastify/fastify-error/pull/86#issuecomment-1301466407
test('ensure that instanceof works accross different installations of the fastify-error module', async (t) => {
const assertsPlanned = 5
t.plan(assertsPlanned)
// We need to create a test environment where fastify-error is installed in two different locations
// and then we will check if the error created in one location is instanceof the error created in the other location
// This is done by creating a test directory with the following structure:
// /
// ├── index.js
// └── node_modules/
// ├── fastify-error/
// │ └── index.js
// └── dep/
// ├── index.js
// └── node_modules/
// └── fastify-error/
// └── index.js
const testDirectoryPrefix = 'fastify-error-instanceof-test-'
const testCwd = path.resolve(os.tmpdir(), `${testDirectoryPrefix}${Math.random().toString(36).substring(2, 15)}`)
fs.mkdirSync(testCwd, { recursive: true })
// Create the index.js. It will be executed as a forked process, so we need to
// use process.send to send messages back to the parent process.
fs.writeFileSync(path.resolve(testCwd, 'index.js'), `
'use strict'
const path = require('node:path')
const { createError, FastifyError } = require('fastify-error')
const { foo } = require('dep')
const actualPathOfFastifyError = require.resolve('fastify-error')
const expectedPathOfFastifyError = path.resolve('node_modules', 'fastify-error', 'index.js')
// Ensure that fastify-error is required from the node_modules directory of the test-project
if (actualPathOfFastifyError !== expectedPathOfFastifyError) {
console.error('actualPathOfFastifyError', actualPathOfFastifyError)
console.error('expectedPathOfFastifyError', expectedPathOfFastifyError)
throw new Error('fastify-error should be required from the node_modules directory of the test-project')
}
const Boom = createError('Boom', 'Boom', 500)
const ChildBoom = createError('ChildBoom', 'Boom', 500, Boom)
const NotChildBoom = createError('NotChildBoom', 'NotChildBoom', 500, Boom)
try {
foo()
} catch (err) {
process.send(err instanceof Error)
process.send(err instanceof FastifyError)
process.send(err instanceof NotChildBoom)
process.send(err instanceof Boom)
process.send(err instanceof ChildBoom)
}
`)
// Create /node_modules/fastify-error directory
// Copy the index.js file to the fastify-error directory
fs.mkdirSync(path.resolve(testCwd, 'node_modules', 'fastify-error'), { recursive: true })
fs.copyFileSync(path.resolve(process.cwd(), 'index.js'), path.resolve(testCwd, 'node_modules', 'fastify-error', 'index.js'))
// Create /node_modules/dep/node_modules/fastify-error directory
// Copy the index.js to the fastify-error directory
fs.mkdirSync(path.resolve(testCwd, 'node_modules', 'dep', 'node_modules', 'fastify-error'), { recursive: true })
fs.copyFileSync(path.resolve(process.cwd(), 'index.js'), path.resolve(testCwd, 'node_modules', 'dep', 'node_modules', 'fastify-error', 'index.js'))
// Create /node_modules/dep/index.js. It will export a function foo which will
// throw an error when called. The error will be an instance of ChildBoom, created
// by the fastify-error module in the node_modules directory of dep.
fs.writeFileSync(path.resolve(testCwd, 'node_modules', 'dep', 'index.js'), `
'use strict'
const path = require('node:path')
const { createError } = require('fastify-error')
const actualPathOfFastifyError = require.resolve('fastify-error')
const expectedPathOfFastifyError = path.resolve('node_modules', 'dep', 'node_modules', 'fastify-error', 'index.js')
// Ensure that fastify-error is required from the node_modules directory of the test-project
if (actualPathOfFastifyError !== expectedPathOfFastifyError) {
console.error('actualPathOfFastifyError', actualPathOfFastifyError)
console.error('expectedPathOfFastifyError', expectedPathOfFastifyError)
throw new Error('fastify-error should be required from the node_modules directory of dep')
}
const Boom = createError('Boom', 'Boom', 500)
const ChildBoom = createError('ChildBoom', 'Boom', 500, Boom)
module.exports.foo = function foo () {
throw new ChildBoom('foo go Boom')
}
`)
const finishedPromise = {
promise: undefined,
reject: undefined,
resolve: undefined,
}
finishedPromise.promise = new Promise((resolve, reject) => {
finishedPromise.resolve = resolve
finishedPromise.reject = reject
})
const child = cp.fork(path.resolve(testCwd, 'index.js'), {
cwd: testCwd,
stdio: 'inherit',
env: {
...process.env,
NODE_OPTIONS: '--no-warnings'
},
})
let messageCount = 0
child.on('message', message => {
try {
switch (messageCount) {
case 0:
t.assert.strictEqual(message, true, 'instanceof Error')
break
case 1:
t.assert.strictEqual(message, true, 'instanceof FastifyError')
break
case 2:
t.assert.strictEqual(message, false, 'instanceof NotChildBoom')
break
case 3:
t.assert.strictEqual(message, true, 'instanceof Boom')
break
case 4:
t.assert.strictEqual(message, true, 'instanceof ChildBoom')
break
}
if (++messageCount === assertsPlanned) {
finishedPromise.resolve()
}
} catch (err) {
finishedPromise.reject(err)
}
})
child.on('error', err => {
finishedPromise.reject(err)
})
await finishedPromise.promise
// Cleanup
// As we are creating the test-setup on the fly in the /tmp directory, we can remove it
// safely when we are done. It is not relevant for the test if the deletion fails.
try {
fs.rmSync(testCwd, { recursive: true, force: true })
} catch {}
})
+3
-0

@@ -17,2 +17,5 @@ name: CI

permissions:
contents: read
jobs:

@@ -19,0 +22,0 @@ test:

@@ -9,3 +9,11 @@ 'use strict'

const FastifyGenericErrorSymbol = Symbol.for('fastify-error-generic')
function createError (code, message, statusCode = 500, Base = Error, captureStackTrace = createError.captureStackTrace) {
const shouldCreateFastifyGenericError = code === FastifyGenericErrorSymbol
if (shouldCreateFastifyGenericError) {
code = 'FST_ERR'
}
if (!code) throw new Error('Fastify error code must not be empty')

@@ -17,2 +25,4 @@ if (!message) throw new Error('Fastify error message must not be empty')

const FastifySpecificErrorSymbol = Symbol.for(`fastify-error ${code}`)
function FastifyError (...args) {

@@ -43,5 +53,37 @@ if (!new.target) {

configurable: true
},
[FastifyGenericErrorSymbol]: {
value: true,
enumerable: false,
writable: false,
configurable: false
},
[FastifySpecificErrorSymbol]: {
value: true,
enumerable: false,
writable: false,
configurable: false
}
})
if (shouldCreateFastifyGenericError) {
Object.defineProperty(FastifyError, Symbol.hasInstance, {
value (instance) {
return instance && instance[FastifyGenericErrorSymbol]
},
configurable: false,
writable: false,
enumerable: false
})
} else {
Object.defineProperty(FastifyError, Symbol.hasInstance, {
value (instance) {
return instance && instance[FastifySpecificErrorSymbol]
},
configurable: false,
writable: false,
enumerable: false
})
}
FastifyError.prototype[Symbol.toStringTag] = 'Error'

@@ -56,4 +98,7 @@

const FastifyErrorConstructor = createError(FastifyGenericErrorSymbol, 'Fastify Error', 500, Error)
module.exports = createError
module.exports.FastifyError = FastifyErrorConstructor
module.exports.default = createError
module.exports.createError = createError
+2
-2
{
"name": "@fastify/error",
"version": "4.1.0",
"version": "4.2.0",
"description": "A small utility, used by Fastify itself, for generating consistent error objects across your codebase and plugins.",

@@ -65,3 +65,3 @@ "main": "index.js",

"neostandard": "^0.12.0",
"tsd": "^0.31.0"
"tsd": "^0.32.0"
},

@@ -68,0 +68,0 @@ "tsd": {

@@ -18,3 +18,3 @@ # @fastify/error

```
```js
createError(code, message [, statusCode [, Base [, captureStackTrace]]])

@@ -62,4 +62,81 @@ ```

### instanceof
All errors created with `createError` will be instances of the base error constructor you provided, or `Error` if none was provided.
```js
const createError = require('@fastify/error')
const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError)
const customError = new CustomError('world')
console.log(customError instanceof CustomError) // true
console.log(customError instanceof TypeError) // true
console.log(customError instanceof Error) // true
```
All instantiated errors are instances of the `FastifyError` class, which can be required directly from the module.
```js
const { createError, FastifyError } = require('@fastify/error')
const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError)
const customError = new CustomError('world')
console.log(customError instanceof FastifyError) // true
```
A `FastifyError` created by `createError` can extend another `FastifyError` while maintaining correct `instanceof` behavior.
```js
const { createError, FastifyError } = require('@fastify/error')
const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError)
const ChildCustomError = createError('CHILD_ERROR_CODE', 'Hello %s', 500, CustomError)
const customError = new ChildCustomError('world')
console.log(customError instanceof ChildCustomError) // true
console.log(customError instanceof CustomError) // true
console.log(customError instanceof FastifyError) // true
console.log(customError instanceof TypeError) // true
console.log(customError instanceof Error) // true
```
If `fastify-error` is installed multiple times directly or as a transitive dependency, `instanceof` checks for errors created by `createError` will still work correctly across these installations, as long as their error codes (e.g., `FST_ERR_CUSTOM_ERROR`) are identical.
```js
const { createError, FastifyError } = require('@fastify/error')
// CustomError from `@fastify/some-plugin` is created with `createError` and
// has its own `@fastify/error` installation as dependency. CustomError has
// FST_ERR_CUSTOM_ERROR as code.
const { CustomError: CustomErrorFromPlugin } = require('@fastify/some-plugin')
const CustomError = createError('FST_ERR_CUSTOM_ERROR', 'Hello %s', 500)
const customError = new CustomError('world')
const customErrorFromPlugin = new CustomErrorFromPlugin('world')
console.log(customError instanceof CustomError) // true
console.log(customError instanceof CustomErrorFromPlugin) // true
console.log(customErrorFromPlugin instanceof CustomError) // true
console.log(customErrorFromPlugin instanceof CustomErrorFromPlugin) // true
```
Changing the code of an instantiated Error will not change the result of the `instanceof` operator.
```js
const { createError, FastifyError } = require('@fastify/error')
const CustomError = createError('ERROR_CODE', 'Hello %s', 500, TypeError)
const AnotherCustomError = createError('ANOTHER_ERROR_CODE', 'Hello %s', 500, CustomError)
const customError = new CustomError('world')
customError.code = 'ANOTHER_ERROR_CODE'
console.log(customError instanceof CustomError) // true
console.log(customError instanceof AnotherCustomError) // false
```
## License
Licensed under [MIT](./LICENSE).
'use strict'
const test = require('node:test')
const createError = require('..')
const { createError, FastifyError } = require('..')

@@ -224,1 +224,10 @@ test('Create error with zero parameter', (t) => {

})
test('check if FastifyError is instantiable', (t) => {
t.plan(2)
const err = new FastifyError()
t.assert.ok(err instanceof FastifyError)
t.assert.ok(err instanceof Error)
})

@@ -43,2 +43,4 @@ declare function createError<C extends string, SC extends number, Arg extends unknown[] = [any?, any?, any?]> (

export const FastifyError: FastifyErrorConstructor
export const createError: CreateError

@@ -45,0 +47,0 @@ export { createError as default }

@@ -80,1 +80,14 @@ import createError, { FastifyError, FastifyErrorConstructor } from '..'

CustomErrorWithErrorConstructor({ cause: new Error('Error') })
const customErrorWithErrorConstructor = CustomErrorWithErrorConstructor()
if (customErrorWithErrorConstructor instanceof FastifyError) {
expectType<'ERROR_CODE'>(customErrorWithErrorConstructor.code)
expectType<string>(customErrorWithErrorConstructor.message)
expectType<500>(customErrorWithErrorConstructor.statusCode)
}
const error = new FastifyError('ERROR_CODE', 'message', 500)
if (error instanceof FastifyError) {
expectType<string>(error.code)
expectType<string>(error.message)
expectType<number | undefined>(error.statusCode)
}