Comparing version 8.2.1 to 8.3.0
393
boot.js
'use strict' | ||
const fastq = require('fastq') | ||
const EE = require('events').EventEmitter | ||
const inherits = require('util').inherits | ||
const EE = require('node:events').EventEmitter | ||
const inherits = require('node:util').inherits | ||
const { | ||
AVV_ERR_EXPOSE_ALREADY_DEFINED, | ||
AVV_ERR_CALLBACK_NOT_FN, | ||
AVV_ERR_PLUGIN_NOT_VALID, | ||
AVV_ERR_ROOT_PLG_BOOTED, | ||
AVV_ERR_READY_TIMEOUT | ||
AVV_ERR_READY_TIMEOUT, | ||
AVV_ERR_ATTRIBUTE_ALREADY_DEFINED | ||
} = require('./lib/errors') | ||
const TimeTree = require('./time-tree') | ||
const Plugin = require('./plugin') | ||
const debug = require('debug')('avvio') | ||
const kAvvio = Symbol('kAvvio') | ||
const kThenifyDoNotWrap = Symbol('kThenifyDoNotWrap') | ||
const { | ||
kAvvio, | ||
kIsOnCloseHandler | ||
} = require('./lib/symbols') | ||
const { TimeTree } = require('./lib/time-tree') | ||
const { Plugin } = require('./lib/plugin') | ||
const { debug } = require('./lib/debug') | ||
const { validatePlugin } = require('./lib/validate-plugin') | ||
const { isBundledOrTypescriptPlugin } = require('./lib/is-bundled-or-typescript-plugin') | ||
const { isPromiseLike } = require('./lib/is-promise-like') | ||
const { thenify } = require('./lib/thenify') | ||
const { executeWithThenable } = require('./lib/execute-with-thenable') | ||
function wrap (server, opts, instance) { | ||
const expose = opts.expose || {} | ||
const useKey = expose.use || 'use' | ||
const afterKey = expose.after || 'after' | ||
const readyKey = expose.ready || 'ready' | ||
const onCloseKey = expose.onClose || 'onClose' | ||
const closeKey = expose.close || 'close' | ||
if (server[useKey]) { | ||
throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(useKey) | ||
} | ||
if (server[afterKey]) { | ||
throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(afterKey) | ||
} | ||
if (server[readyKey]) { | ||
throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(readyKey) | ||
} | ||
server[useKey] = function (fn, opts) { | ||
instance.use(fn, opts) | ||
return this | ||
} | ||
Object.defineProperty(server, 'then', { get: thenify.bind(instance) }) | ||
server[kAvvio] = true | ||
server[afterKey] = function (func) { | ||
if (typeof func !== 'function') { | ||
return instance._loadRegistered() | ||
} | ||
instance.after(encapsulateThreeParam(func, this)) | ||
return this | ||
} | ||
server[readyKey] = function (func) { | ||
if (func && typeof func !== 'function') { | ||
throw new AVV_ERR_CALLBACK_NOT_FN(readyKey, typeof func) | ||
} | ||
return instance.ready(func ? encapsulateThreeParam(func, this) : undefined) | ||
} | ||
server[onCloseKey] = function (func) { | ||
if (typeof func !== 'function') { | ||
throw new AVV_ERR_CALLBACK_NOT_FN(onCloseKey, typeof func) | ||
} | ||
instance.onClose(encapsulateTwoParam(func, this)) | ||
return this | ||
} | ||
server[closeKey] = function (func) { | ||
if (func && typeof func !== 'function') { | ||
throw new AVV_ERR_CALLBACK_NOT_FN(closeKey, typeof func) | ||
} | ||
if (func) { | ||
instance.close(encapsulateThreeParam(func, this)) | ||
return this | ||
} | ||
// this is a Promise | ||
return instance.close() | ||
} | ||
} | ||
function Boot (server, opts, done) { | ||
@@ -98,24 +39,24 @@ if (typeof server === 'function' && arguments.length === 1) { | ||
opts = opts || {} | ||
opts.autostart = opts.autostart !== false | ||
opts.timeout = Number(opts.timeout) || 0 | ||
opts.expose = opts.expose || {} | ||
if (!(this instanceof Boot)) { | ||
const instance = new Boot(server, opts, done) | ||
if (!new.target) { | ||
return new Boot(server, opts, done) | ||
} | ||
if (server) { | ||
wrap(server, opts, instance) | ||
} | ||
this._server = server || this | ||
this._opts = opts | ||
return instance | ||
if (server) { | ||
this._expose() | ||
} | ||
if (opts.autostart !== false) { | ||
opts.autostart = true | ||
} | ||
/** | ||
* @type {Array<Plugin>} | ||
*/ | ||
this._current = [] | ||
server = server || this | ||
this._error = null | ||
this._timeout = Number(opts.timeout) || 0 | ||
this._server = server | ||
this._current = [] | ||
this._error = null | ||
this._isOnCloseHandlerKey = Symbol('isOnCloseHandler') | ||
this._lastUsed = null | ||
@@ -150,11 +91,12 @@ | ||
this._doStart = null | ||
this._root = new Plugin(this, root.bind(this), opts, false, 0) | ||
this._root.once('start', (serverName, funcName, time) => { | ||
const nodeId = this.pluginTree.start(null, funcName, time) | ||
this._root.once('loaded', (serverName, funcName, time) => { | ||
this.pluginTree.stop(nodeId, time) | ||
}) | ||
}) | ||
Plugin.loadPlugin.call(this, this._root, (err) => { | ||
const instance = this | ||
this._root = new Plugin(fastq(this, this._loadPluginNextTick, 1), function root (server, opts, done) { | ||
instance._doStart = done | ||
opts.autostart && instance.start() | ||
}, opts, false, 0) | ||
this._trackPluginLoading(this._root) | ||
this._loadPlugin(this._root, (err) => { | ||
debug('root plugin ready') | ||
@@ -164,4 +106,4 @@ try { | ||
this._root = null | ||
} catch (prereadyError) { | ||
err = err || this._error || prereadyError | ||
} catch (preReadyError) { | ||
err = err || this._error || preReadyError | ||
} | ||
@@ -181,9 +123,2 @@ | ||
function root (s, opts, done) { | ||
this._doStart = done | ||
if (opts.autostart) { | ||
this.start() | ||
} | ||
} | ||
inherits(Boot, EE) | ||
@@ -204,14 +139,2 @@ | ||
function assertPlugin (plugin) { | ||
// Faux modules are modules built with TypeScript | ||
// or Babel that they export a .default property. | ||
if (plugin && typeof plugin === 'object' && typeof plugin.default === 'function') { | ||
plugin = plugin.default | ||
} | ||
if (!(plugin && (typeof plugin === 'function' || typeof plugin.then === 'function'))) { | ||
throw new AVV_ERR_PLUGIN_NOT_VALID(typeof plugin) | ||
} | ||
return plugin | ||
} | ||
Boot.prototype[kAvvio] = true | ||
@@ -230,5 +153,5 @@ | ||
// if the root plugin is not loaded, let's resume that | ||
// so one can use after() befor calling ready | ||
// so one can use after() before calling ready | ||
if (weNeedToStart) { | ||
process.nextTick(() => this._root.q.resume()) | ||
process.nextTick(() => this._root.queue.resume()) | ||
} | ||
@@ -245,4 +168,7 @@ | ||
Boot.prototype._addPlugin = function (plugin, opts, isAfter) { | ||
plugin = assertPlugin(plugin) | ||
Boot.prototype._addPlugin = function (pluginFn, opts, isAfter) { | ||
if (isBundledOrTypescriptPlugin(pluginFn)) { | ||
pluginFn = pluginFn.default | ||
} | ||
validatePlugin(pluginFn) | ||
opts = opts || {} | ||
@@ -257,22 +183,89 @@ | ||
const obj = new Plugin(this, plugin, opts, isAfter) | ||
obj.once('start', (serverName, funcName, time) => { | ||
const nodeId = this.pluginTree.start(current.name, funcName, time) | ||
obj.once('loaded', (serverName, funcName, time) => { | ||
this.pluginTree.stop(nodeId, time) | ||
}) | ||
}) | ||
const plugin = new Plugin(fastq(this, this._loadPluginNextTick, 1), pluginFn, opts, isAfter, this._opts.timeout) | ||
this._trackPluginLoading(plugin) | ||
if (current.loaded) { | ||
throw new Error(obj.name, current.name) | ||
throw new Error(plugin.name, current.name) | ||
} | ||
// we add the plugin to be loaded at the end of the current queue | ||
current.enqueue(obj, (err) => { | ||
if (err) { | ||
this._error = err | ||
current.enqueue(plugin, (err) => { err && (this._error = err) }) | ||
return plugin | ||
} | ||
Boot.prototype._expose = function _expose () { | ||
const instance = this | ||
const server = instance._server | ||
const { | ||
use: useKey = 'use', | ||
after: afterKey = 'after', | ||
ready: readyKey = 'ready', | ||
onClose: onCloseKey = 'onClose', | ||
close: closeKey = 'close' | ||
} = this._opts.expose | ||
if (server[useKey]) { | ||
throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(useKey, 'use') | ||
} | ||
server[useKey] = function (fn, opts) { | ||
instance.use(fn, opts) | ||
return this | ||
} | ||
if (server[afterKey]) { | ||
throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(afterKey, 'after') | ||
} | ||
server[afterKey] = function (func) { | ||
if (typeof func !== 'function') { | ||
return instance._loadRegistered() | ||
} | ||
}) | ||
instance.after(encapsulateThreeParam(func, this)) | ||
return this | ||
} | ||
return obj | ||
if (server[readyKey]) { | ||
throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(readyKey, 'ready') | ||
} | ||
server[readyKey] = function (func) { | ||
if (func && typeof func !== 'function') { | ||
throw new AVV_ERR_CALLBACK_NOT_FN(readyKey, typeof func) | ||
} | ||
return instance.ready(func ? encapsulateThreeParam(func, this) : undefined) | ||
} | ||
if (server[onCloseKey]) { | ||
throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(onCloseKey, 'onClose') | ||
} | ||
server[onCloseKey] = function (func) { | ||
if (typeof func !== 'function') { | ||
throw new AVV_ERR_CALLBACK_NOT_FN(onCloseKey, typeof func) | ||
} | ||
instance.onClose(encapsulateTwoParam(func, this)) | ||
return this | ||
} | ||
if (server[closeKey]) { | ||
throw new AVV_ERR_EXPOSE_ALREADY_DEFINED(closeKey, 'close') | ||
} | ||
server[closeKey] = function (func) { | ||
if (func && typeof func !== 'function') { | ||
throw new AVV_ERR_CALLBACK_NOT_FN(closeKey, typeof func) | ||
} | ||
if (func) { | ||
instance.close(encapsulateThreeParam(func, this)) | ||
return this | ||
} | ||
// this is a Promise | ||
return instance.close() | ||
} | ||
if (server.then) { | ||
throw new AVV_ERR_ATTRIBUTE_ALREADY_DEFINED('then') | ||
} | ||
Object.defineProperty(server, 'then', { get: thenify.bind(instance) }) | ||
server[kAvvio] = true | ||
} | ||
@@ -299,12 +292,8 @@ | ||
if (typeof func !== 'function') { | ||
throw new Error('not a function') | ||
throw new AVV_ERR_CALLBACK_NOT_FN('onClose', typeof func) | ||
} | ||
func[this._isOnCloseHandlerKey] = true | ||
this._closeQ.unshift(func, callback.bind(this)) | ||
func[kIsOnCloseHandler] = true | ||
this._closeQ.unshift(func, (err) => { err && (this._error = err) }) | ||
function callback (err) { | ||
if (err) this._error = err | ||
} | ||
return this | ||
@@ -374,4 +363,18 @@ } | ||
/** | ||
* @param {Plugin} plugin | ||
* @returns {void} | ||
*/ | ||
Boot.prototype._trackPluginLoading = function (plugin) { | ||
const parentName = this._current[0]?.name || null | ||
plugin.once('start', (serverName, funcName, time) => { | ||
const nodeId = this.pluginTree.start(parentName || null, funcName, time) | ||
plugin.once('loaded', (serverName, funcName, time) => { | ||
this.pluginTree.stop(nodeId, time) | ||
}) | ||
}) | ||
} | ||
Boot.prototype.prettyPrint = function () { | ||
return this.pluginTree.prittyPrint() | ||
return this.pluginTree.prettyPrint() | ||
} | ||
@@ -383,38 +386,72 @@ | ||
function noop () { } | ||
/** | ||
* @callback LoadPluginCallback | ||
* @param {Error} [err] | ||
*/ | ||
function thenify () { | ||
// If the instance is ready, then there is | ||
// nothing to await. This is true during | ||
// await server.ready() as ready() resolves | ||
// with the server, end we will end up here | ||
// because of automatic promise chaining. | ||
if (this.booted) { | ||
debug('thenify returning null because we are already booted') | ||
/** | ||
* Load a plugin | ||
* | ||
* @param {Plugin} plugin | ||
* @param {LoadPluginCallback} callback | ||
*/ | ||
Boot.prototype._loadPlugin = function (plugin, callback) { | ||
const instance = this | ||
if (isPromiseLike(plugin.func)) { | ||
plugin.func.then((fn) => { | ||
if (typeof fn.default === 'function') { | ||
fn = fn.default | ||
} | ||
plugin.func = fn | ||
this._loadPlugin(plugin, callback) | ||
}, callback) | ||
return | ||
} | ||
// Calling resolve(this._server) would fetch the then | ||
// property on the server, which will lead it here. | ||
// If we do not break the recursion, we will loop | ||
// forever. | ||
if (this[kThenifyDoNotWrap]) { | ||
this[kThenifyDoNotWrap] = false | ||
const last = instance._current[0] | ||
// place the plugin at the top of _current | ||
instance._current.unshift(plugin) | ||
if (instance._error && !plugin.isAfter) { | ||
debug('skipping loading of plugin as instance errored and it is not an after', plugin.name) | ||
process.nextTick(execCallback) | ||
return | ||
} | ||
debug('thenify') | ||
return (resolve, reject) => { | ||
const p = this._loadRegistered() | ||
return p.then(() => { | ||
this[kThenifyDoNotWrap] = true | ||
return resolve(this._server) | ||
}, reject) | ||
let server = (last && last.server) || instance._server | ||
if (!plugin.isAfter) { | ||
// Skip override for after | ||
try { | ||
server = instance.override(server, plugin.func, plugin.options) | ||
} catch (overrideErr) { | ||
debug('override errored', plugin.name) | ||
return execCallback(overrideErr) | ||
} | ||
} | ||
plugin.exec(server, execCallback) | ||
function execCallback (err) { | ||
plugin.finish(err, (err) => { | ||
instance._current.shift() | ||
callback(err) | ||
}) | ||
} | ||
} | ||
/** | ||
* Delays plugin loading until the next tick to ensure any bound `_after` callbacks have a chance | ||
* to run prior to executing the next plugin | ||
*/ | ||
Boot.prototype._loadPluginNextTick = function (plugin, callback) { | ||
process.nextTick(this._loadPlugin.bind(this), plugin, callback) | ||
} | ||
function noop () { } | ||
function callWithCbOrNextTick (func, cb) { | ||
const context = this._server | ||
const err = this._error | ||
let res | ||
@@ -425,17 +462,7 @@ // with this the error will appear just in the next after/ready callback | ||
this._error = err | ||
res = func() | ||
if (res && !res[kAvvio] && typeof res.then === 'function') { | ||
res.then(() => process.nextTick(cb), (e) => process.nextTick(cb, e)) | ||
} else { | ||
process.nextTick(cb) | ||
} | ||
executeWithThenable(func, [], cb) | ||
} else if (func.length === 1) { | ||
res = func(err) | ||
if (res && !res[kAvvio] && typeof res.then === 'function') { | ||
res.then(() => process.nextTick(cb), (e) => process.nextTick(cb, e)) | ||
} else { | ||
process.nextTick(cb) | ||
} | ||
executeWithThenable(func, [err], cb) | ||
} else { | ||
if (this._timeout === 0) { | ||
if (this._opts.timeout === 0) { | ||
const wrapCb = (err) => { | ||
@@ -459,3 +486,3 @@ this._error = err | ||
const name = func.name | ||
debug('setting up ready timeout', name, this._timeout) | ||
debug('setting up ready timeout', name, this._opts.timeout) | ||
let timer = setTimeout(() => { | ||
@@ -468,3 +495,3 @@ debug('timed out', name) | ||
cb(toutErr) | ||
}, this._timeout) | ||
}, this._opts.timeout) | ||
@@ -491,3 +518,3 @@ if (func.length === 2) { | ||
const context = this._server | ||
const isOnCloseHandler = func[this._isOnCloseHandlerKey] | ||
const isOnCloseHandler = func[kIsOnCloseHandler] | ||
if (func.length === 0 || func.length === 1) { | ||
@@ -494,0 +521,0 @@ let promise |
@@ -68,3 +68,3 @@ import { EventEmitter } from "events"; | ||
interface Use<I, C = context<I>> { | ||
<O>(fn: avvio.Plugin<O, I>, options?: O): C; | ||
<O>(fn: avvio.Plugin<O, I>, options?: O | ((server: C) => O)): C; | ||
} | ||
@@ -71,0 +71,0 @@ |
'use strict' | ||
// Code inherited from fastify-error | ||
const { inherits, format } = require('util') | ||
function createError (code, message, Base = Error) { | ||
if (!code) throw new Error('Avvio error code must not be empty') | ||
if (!message) throw new Error('Avvio base error message must not be empty') | ||
const { createError } = require('@fastify/error') | ||
function AvvioError (a, b, c) { | ||
if (!new.target) { | ||
return new AvvioError(a, b, c) | ||
} | ||
Error.captureStackTrace(this, AvvioError) | ||
this.code = code | ||
this.message = message | ||
this.name = 'AvvioError' | ||
// more performant than spread (...) operator | ||
if (a && b && c) { | ||
this.message = format(message, a, b, c) | ||
} else if (a && b) { | ||
this.message = format(message, a, b) | ||
} else if (a) { | ||
this.message = format(message, a) | ||
} else { | ||
this.message = message | ||
} | ||
} | ||
AvvioError.prototype[Symbol.toStringTag] = 'Error' | ||
AvvioError.prototype.toString = function () { | ||
return `${this.name} [${this.code}]: ${this.message}` | ||
} | ||
inherits(AvvioError, Base) | ||
return AvvioError | ||
} | ||
module.exports = { | ||
createError, | ||
AVV_ERR_EXPOSE_ALREADY_DEFINED: createError( | ||
'AVV_ERR_EXPOSE_ALREADY_DEFINED', | ||
"'%s' () is already defined, specify an expose option" | ||
"'%s' is already defined, specify an expose option for '%s'" | ||
), | ||
AVV_ERR_ATTRIBUTE_ALREADY_DEFINED: createError( | ||
'AVV_ERR_ATTRIBUTE_ALREADY_DEFINED', | ||
"'%s' is already defined" | ||
), | ||
AVV_ERR_CALLBACK_NOT_FN: createError( | ||
@@ -57,3 +23,3 @@ 'AVV_ERR_CALLBACK_NOT_FN', | ||
AVV_ERR_ROOT_PLG_BOOTED: createError( | ||
'AVV_ERR_PLUGIN_NOT_VALID', | ||
'AVV_ERR_ROOT_PLG_BOOTED', | ||
'Root plugin has already booted' | ||
@@ -68,3 +34,7 @@ ), | ||
"Plugin did not start in time: '%s'. You may have forgotten to call 'done' function or to resolve a Promise" | ||
), | ||
AVV_ERR_PLUGIN_EXEC_TIMEOUT: createError( | ||
'AVV_ERR_PLUGIN_EXEC_TIMEOUT', | ||
"Plugin did not start in time: '%s'. You may have forgotten to call 'done' function or to resolve a Promise" | ||
) | ||
} |
{ | ||
"name": "avvio", | ||
"version": "8.2.1", | ||
"version": "8.3.0", | ||
"description": "Asynchronous bootstrapping of Node applications", | ||
"main": "boot.js", | ||
"type": "commonjs", | ||
"scripts": { | ||
"test": "standard && tap -J test/*test.js && npm run typescript", | ||
"typescript": "tsc --project ./test/types/tsconfig.json" | ||
"lint": "standard", | ||
"lint:fix": "standard --fix", | ||
"test": "npm run test:unit && npm run test:typescript", | ||
"test:unit": "tap", | ||
"test:typescript": "tsc --project ./test/types/tsconfig.json" | ||
}, | ||
"precommit": "test", | ||
"precommit": [ | ||
"lint", | ||
"test" | ||
], | ||
"repository": { | ||
@@ -35,15 +42,14 @@ "type": "git", | ||
"@fastify/pre-commit": "^2.0.2", | ||
"@types/node": "^18.0.0", | ||
"@types/node": "^20.1.0", | ||
"express": "^4.17.1", | ||
"semver": "^7.1.3", | ||
"standard": "^17.0.0", | ||
"tap": "^16.0.0", | ||
"then-sleep": "^1.0.1", | ||
"typescript": "^4.0.2" | ||
"typescript": "^5.0.2" | ||
}, | ||
"dependencies": { | ||
"@fastify/error": "^3.3.0", | ||
"archy": "^1.0.0", | ||
"debug": "^4.0.0", | ||
"fastq": "^1.6.1" | ||
"fastq": "^1.17.1" | ||
} | ||
} |
@@ -475,3 +475,3 @@ # avvio | ||
```js | ||
const assert = require('assert') | ||
const assert = require('node:assert') | ||
const server = { count: 0 } | ||
@@ -620,7 +620,7 @@ const app = require('avvio')(server) | ||
{ | ||
"label": "bound root", | ||
"label": "root", | ||
"start": 1550245184665, | ||
"nodes": [ | ||
{ | ||
"parent": "bound root", | ||
"parent": "root", | ||
"start": 1550245184665, | ||
@@ -642,3 +642,3 @@ "label": "first", | ||
{ | ||
"parent": "bound root", | ||
"parent": "root", | ||
"start": 1550245184709, | ||
@@ -691,2 +691,2 @@ "label": "third", | ||
[MIT]: ./LICENSE | ||
[example]: ./example.js | ||
[example]: ./examples/example.js |
@@ -6,3 +6,7 @@ 'use strict' | ||
const { test } = require('tap') | ||
const sleep = require('then-sleep') | ||
const sleep = function (ms) { | ||
return new Promise(function (resolve) { | ||
setTimeout(resolve, ms) | ||
}) | ||
} | ||
@@ -9,0 +13,0 @@ const boot = require('..') |
@@ -5,6 +5,6 @@ 'use strict' | ||
const boot = require('..') | ||
const { promisify } = require('util') | ||
const { promisify } = require('node:util') | ||
const sleep = promisify(setTimeout) | ||
const fs = require('fs').promises | ||
const path = require('path') | ||
const fs = require('node:fs').promises | ||
const path = require('node:path') | ||
@@ -11,0 +11,0 @@ test('await after - nested plugins with same tick callbacks', async (t) => { |
'use strict' | ||
const { test } = require('tap') | ||
const { promisify } = require('util') | ||
const { promisify } = require('node:util') | ||
const sleep = promisify(setTimeout) | ||
@@ -6,0 +6,0 @@ const boot = require('..') |
@@ -64,3 +64,3 @@ 'use strict' | ||
test('boot an app with a plugin and a callback', (t) => { | ||
test('boot an app with a plugin and a callback /1', (t) => { | ||
t.plan(2) | ||
@@ -78,2 +78,15 @@ | ||
test('boot an app with a plugin and a callback /2', (t) => { | ||
t.plan(2) | ||
const app = boot({}, () => { | ||
t.pass('booted') | ||
}) | ||
app.use(function (server, opts, done) { | ||
t.pass('plugin loaded') | ||
done() | ||
}) | ||
}) | ||
test('boot a plugin with a custom server', (t) => { | ||
@@ -102,3 +115,3 @@ t.plan(4) | ||
test('custom instance should inherits avvio methods', (t) => { | ||
test('custom instance should inherits avvio methods /1', (t) => { | ||
t.plan(6) | ||
@@ -132,2 +145,31 @@ | ||
test('custom instance should inherits avvio methods /2', (t) => { | ||
t.plan(6) | ||
const server = {} | ||
const app = new boot(server, {}) // eslint-disable-line new-cap | ||
server.use(function (s, opts, done) { | ||
t.equal(s, server, 'the first argument is the server') | ||
t.same(opts, {}, 'no options') | ||
done() | ||
}).after(() => { | ||
t.ok('after called') | ||
}) | ||
server.onClose(() => { | ||
t.ok('onClose called') | ||
}) | ||
server.ready(() => { | ||
t.ok('ready called') | ||
}) | ||
app.on('start', () => { | ||
server.close(() => { | ||
t.pass('booted') | ||
}) | ||
}) | ||
}) | ||
test('boot a plugin with options', (t) => { | ||
@@ -134,0 +176,0 @@ t.plan(3) |
@@ -43,32 +43,2 @@ 'use strict' | ||
;['use', 'after', 'ready'].forEach((key) => { | ||
test('throws if ' + key + ' is already there', (t) => { | ||
t.plan(1) | ||
const app = {} | ||
app[key] = () => {} | ||
try { | ||
boot(app) | ||
t.fail('error must happen') | ||
} catch (err) { | ||
t.equal(err.message, `'${key}' () is already defined, specify an expose option`) | ||
} | ||
}) | ||
test('support expose for ' + key, (t) => { | ||
const app = {} | ||
app[key] = () => {} | ||
const expose = {} | ||
expose[key] = 'muahah' | ||
boot(app, { | ||
expose | ||
}) | ||
t.end() | ||
}) | ||
}) | ||
test('chainable standalone with server', (t) => { | ||
@@ -75,0 +45,0 @@ t.plan(6) |
@@ -5,2 +5,3 @@ 'use strict' | ||
const boot = require('..') | ||
const { AVV_ERR_CALLBACK_NOT_FN } = require('../lib/errors') | ||
@@ -498,3 +499,3 @@ test('boot an app with a plugin', (t) => { | ||
app.use(function (server, opts, done) { | ||
t.throws(() => app.onClose({}), { message: 'not a function' }) | ||
t.throws(() => app.onClose({}), new AVV_ERR_CALLBACK_NOT_FN('onClose', 'object')) | ||
done() | ||
@@ -501,0 +502,0 @@ }) |
'use strict' | ||
const { test } = require('tap') | ||
const { createError } = require('../lib/errors') | ||
const errors = require('../lib/errors') | ||
const expectedErrorName = 'AvvioError' | ||
test('Correct codes of AvvioErrors', t => { | ||
const testcases = [ | ||
'AVV_ERR_EXPOSE_ALREADY_DEFINED', | ||
'AVV_ERR_ATTRIBUTE_ALREADY_DEFINED', | ||
'AVV_ERR_CALLBACK_NOT_FN', | ||
'AVV_ERR_PLUGIN_NOT_VALID', | ||
'AVV_ERR_ROOT_PLG_BOOTED', | ||
'AVV_ERR_PARENT_PLG_LOADED', | ||
'AVV_ERR_READY_TIMEOUT', | ||
'AVV_ERR_PLUGIN_EXEC_TIMEOUT' | ||
] | ||
test('Create error with zero parameter', t => { | ||
t.plan(5) | ||
const NewError = createError('CODE', 'Not available') | ||
const err = new NewError() | ||
t.ok(err instanceof Error) | ||
t.ok(err.stack) | ||
t.equal(err.name, expectedErrorName) | ||
t.equal(err.message, 'Not available') | ||
t.equal(err.code, 'CODE') | ||
}) | ||
t.plan(testcases.length + 1) | ||
// errors.js exposes errors and the createError fn | ||
t.equal(testcases.length, Object.keys(errors).length) | ||
test('Create error with 1 parameter', t => { | ||
t.plan(5) | ||
const NewError = createError('CODE', 'hey %s') | ||
const err = new NewError('alice') | ||
t.ok(err instanceof Error) | ||
t.ok(err.stack) | ||
t.equal(err.name, expectedErrorName) | ||
t.equal(err.message, 'hey alice') | ||
t.equal(err.code, 'CODE') | ||
}) | ||
test('Create error with 2 parameters', t => { | ||
t.plan(5) | ||
const NewError = createError('CODE', 'hey %s, I like your %s') | ||
const err = new NewError('alice', 'attitude') | ||
t.ok(err instanceof Error) | ||
t.ok(err.stack) | ||
t.equal(err.name, expectedErrorName) | ||
t.equal(err.message, 'hey alice, I like your attitude') | ||
t.equal(err.code, 'CODE') | ||
}) | ||
test('Create error with 3 parameters', t => { | ||
t.plan(5) | ||
const NewError = createError('CODE', 'hey %s, I like your %s %s') | ||
const err = new NewError('alice', 'attitude', 'see you') | ||
t.ok(err instanceof Error) | ||
t.ok(err.stack) | ||
t.equal(err.name, expectedErrorName) | ||
t.equal(err.message, 'hey alice, I like your attitude see you') | ||
t.equal(err.code, 'CODE') | ||
}) | ||
test('Should throw when error code has no Avvio code', t => { | ||
t.plan(1) | ||
try { | ||
createError() | ||
} catch (err) { | ||
t.equal(err.message, 'Avvio error code must not be empty') | ||
for (const testcase of testcases) { | ||
const error = new errors[testcase]() | ||
t.equal(error.code, testcase) | ||
} | ||
}) | ||
test('Should throw when error code has no message', t => { | ||
t.plan(1) | ||
try { | ||
createError('code') | ||
} catch (err) { | ||
t.equal(err.message, 'Avvio base error message must not be empty') | ||
} | ||
}) | ||
test('Create error with different base', t => { | ||
t.plan(6) | ||
const NewError = createError('CODE', 'hey %s', TypeError) | ||
const err = new NewError('dude') | ||
t.ok(err instanceof Error) | ||
t.ok(err instanceof TypeError) | ||
t.ok(err.stack) | ||
t.equal(err.name, expectedErrorName) | ||
t.equal(err.message, 'hey dude') | ||
t.equal(err.code, 'CODE') | ||
}) | ||
test('AvvioError.toString returns code', t => { | ||
t.plan(1) | ||
const NewError = createError('CODE', 'foo') | ||
const err = new NewError() | ||
t.equal(err.toString(), 'AvvioError [CODE]: foo') | ||
}) | ||
test('Create the error without the new keyword', t => { | ||
t.plan(5) | ||
const NewError = createError('CODE', 'Not available') | ||
const err = NewError() | ||
t.ok(err instanceof Error) | ||
t.ok(err.stack) | ||
t.equal(err.name, expectedErrorName) | ||
t.equal(err.message, 'Not available') | ||
t.equal(err.code, 'CODE') | ||
}) |
'use strict' | ||
const { test } = require('tap') | ||
const semver = require('semver') | ||
test('support import', { skip: semver.lt(process.versions.node, '13.3.0') }, (t) => { | ||
test('support esm import', (t) => { | ||
import('./esm.mjs').then(() => { | ||
@@ -8,0 +7,0 @@ t.pass('esm is supported') |
@@ -5,3 +5,3 @@ 'use strict' | ||
const express = require('express') | ||
const http = require('http') | ||
const http = require('node:http') | ||
const boot = require('..') | ||
@@ -8,0 +8,0 @@ |
@@ -5,2 +5,3 @@ 'use strict' | ||
const boot = require('..') | ||
const { kPluginMeta } = require('../lib/symbols') | ||
@@ -12,3 +13,3 @@ test('plugins get a name from the plugin metadata if it is set', async (t) => { | ||
const func = (app, opts, next) => next() | ||
func[Symbol.for('plugin-meta')] = { name: 'a-test-plugin' } | ||
func[kPluginMeta] = { name: 'a-test-plugin' } | ||
app.use(func) | ||
@@ -18,3 +19,3 @@ await app.ready() | ||
t.match(app.toJSON(), { | ||
label: 'bound root', | ||
label: 'root', | ||
nodes: [ | ||
@@ -35,3 +36,3 @@ { label: 'a-test-plugin' } | ||
t.match(app.toJSON(), { | ||
label: 'bound root', | ||
label: 'root', | ||
nodes: [ | ||
@@ -52,3 +53,3 @@ { label: 'test registration options name' } | ||
t.match(app.toJSON(), { | ||
label: 'bound root', | ||
label: 'root', | ||
nodes: [ | ||
@@ -68,3 +69,3 @@ { label: 'testPlugin' } | ||
t.match(app.toJSON(), { | ||
label: 'bound root', | ||
label: 'root', | ||
nodes: [ | ||
@@ -71,0 +72,0 @@ { label: '(app, opts, next) => next()' } |
@@ -21,3 +21,3 @@ 'use strict' | ||
t.equal(err.message, message('one')) | ||
t.equal(err.code, 'AVV_ERR_READY_TIMEOUT') | ||
t.equal(err.code, 'AVV_ERR_PLUGIN_EXEC_TIMEOUT') | ||
}) | ||
@@ -41,3 +41,3 @@ }) | ||
t.equal(err.message, message('two')) | ||
t.equal(err.code, 'AVV_ERR_READY_TIMEOUT') | ||
t.equal(err.code, 'AVV_ERR_PLUGIN_EXEC_TIMEOUT') | ||
}) | ||
@@ -55,3 +55,3 @@ }) | ||
t.equal(err.message, message('noNext')) | ||
t.equal(err.code, 'AVV_ERR_READY_TIMEOUT') | ||
t.equal(err.code, 'AVV_ERR_PLUGIN_EXEC_TIMEOUT') | ||
}) | ||
@@ -72,3 +72,3 @@ }) | ||
t.equal(err.message, message('function (app, opts, next) { -- // do not call next on purpose - code as name')) | ||
t.equal(err.code, 'AVV_ERR_READY_TIMEOUT') | ||
t.equal(err.code, 'AVV_ERR_PLUGIN_EXEC_TIMEOUT') | ||
}) | ||
@@ -75,0 +75,0 @@ }) |
@@ -18,19 +18,19 @@ 'use strict' | ||
const linesExpected = [/bound root \d+ ms/, | ||
/├── first \d+ ms/, | ||
/├─┬ duplicate \d+ ms/, | ||
/│ └─┬ duplicate \d+ ms/, | ||
/│ {3}└─┬ duplicate \d+ ms/, | ||
/│ {5}└── duplicate \d+ ms/, | ||
/├── second \d+ ms/, | ||
/├─┬ bound _after \d+ ms/, | ||
/│ └── afterInsider \d+ ms/, | ||
/├── bound _after \d+ ms/, | ||
/├─┬ duplicate \d+ ms/, | ||
/│ └─┬ duplicate \d+ ms/, | ||
/│ {3}└── duplicate \d+ ms/, | ||
/├── third \d+ ms/, | ||
/├── bound _after \d+ ms/, | ||
/└─┬ duplicate \d+ ms/, | ||
/ {2}└── duplicate \d+ ms/, | ||
const linesExpected = [/^root \d+ ms$/, | ||
/^├── first \d+ ms$/, | ||
/^├─┬ duplicate \d+ ms$/, | ||
/^│ └─┬ duplicate \d+ ms$/, | ||
/^│ {3}└─┬ duplicate \d+ ms$/, | ||
/^│ {5}└── duplicate \d+ ms$/, | ||
/^├── second \d+ ms$/, | ||
/^├─┬ bound _after \d+ ms$/, | ||
/^│ └── afterInsider \d+ ms$/, | ||
/^├── bound _after \d+ ms$/, | ||
/^├─┬ duplicate \d+ ms$/, | ||
/^│ └─┬ duplicate \d+ ms$/, | ||
/^│ {3}└── duplicate \d+ ms$/, | ||
/^├── third \d+ ms$/, | ||
/^├── bound _after \d+ ms$/, | ||
/^└─┬ duplicate \d+ ms$/, | ||
/^ {2}└── duplicate \d+ ms$/, | ||
'' | ||
@@ -37,0 +37,0 @@ ] |
@@ -17,3 +17,3 @@ 'use strict' | ||
id: 'root', | ||
label: 'bound root', | ||
label: 'root', | ||
start: /\d+/, | ||
@@ -73,3 +73,3 @@ nodes: [] | ||
id: 'root', | ||
label: 'bound root', | ||
label: 'root', | ||
start: /\d+/, | ||
@@ -79,3 +79,3 @@ nodes: [ | ||
id: /.+/, | ||
parent: 'bound root', | ||
parent: 'root', | ||
start: /\d+/, | ||
@@ -82,0 +82,0 @@ label: 'first', |
@@ -38,2 +38,14 @@ import * as avvio from "../../"; | ||
app.use(async (server, options) => {}, | ||
(server) => { | ||
server.use; | ||
server.after; | ||
server.ready; | ||
server.on; | ||
server.start; | ||
server.override; | ||
server.onClose; | ||
server.close; | ||
}); | ||
app.after(err => { | ||
@@ -160,2 +172,14 @@ if (err) throw err; | ||
app.use(async (server, options) => {}, | ||
(server) => { | ||
server.use; | ||
server.after; | ||
server.ready; | ||
server.on; | ||
server.start; | ||
server.override; | ||
server.onClose; | ||
server.close; | ||
}); | ||
app.after(err => { | ||
@@ -275,2 +299,10 @@ if (err) throw err; | ||
app.use(async (server, options) => {}, | ||
((server) => { | ||
server.use; | ||
server.after; | ||
server.ready; | ||
server.typescriptIs; | ||
})); | ||
app.after(err => { | ||
@@ -277,0 +309,0 @@ if (err) throw err; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
179137
6
67
6103
0
0
4
+ Added@fastify/error@^3.3.0
+ Added@fastify/error@3.4.1(transitive)
Updatedfastq@^1.17.1