{"id":13526539,"url":"https://github.com/fastify/avvio","last_synced_at":"2025-04-10T10:47:05.609Z","repository":{"id":36954562,"uuid":"65019333","full_name":"fastify/avvio","owner":"fastify","description":"Asynchronous bootstrapping of Node applications","archived":false,"fork":false,"pushed_at":"2024-10-24T16:19:51.000Z","size":401,"stargazers_count":412,"open_issues_count":9,"forks_count":39,"subscribers_count":17,"default_branch":"master","last_synced_at":"2024-10-29T14:46:45.423Z","etag":null,"topics":["fastify","fastify-library"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fastify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"fastify","open_collective":"fastify"}},"created_at":"2016-08-05T13:09:39.000Z","updated_at":"2024-10-29T14:31:31.000Z","dependencies_parsed_at":"2023-01-17T08:00:52.848Z","dependency_job_id":"38bb0ec6-3cab-4e00-90c1-32fee15301ac","html_url":"https://github.com/fastify/avvio","commit_stats":{"total_commits":367,"total_committers":38,"mean_commits":9.657894736842104,"dds":0.5667574931880108,"last_synced_commit":"3e2e85424e2bbec512d0577126b03697b2c523a1"},"previous_names":["mcollina/boot-in-the-arse","mcollina/avvio"],"tags_count":73,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Favvio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Favvio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Favvio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Favvio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fastify","download_url":"https://codeload.github.com/fastify/avvio/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248201810,"owners_count":21064200,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastify","fastify-library"],"created_at":"2024-08-01T06:01:31.184Z","updated_at":"2025-04-10T10:47:05.401Z","avatar_url":"https://github.com/fastify.png","language":"JavaScript","readme":"# avvio\n\n[![CI](https://github.com/fastify/avvio/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/fastify/avvio/actions/workflows/ci.yml)\n[![NPM version](https://img.shields.io/npm/v/avvio.svg?style=flat)](https://www.npmjs.com/package/avvio)\n[![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)\n\nAsynchronous bootstrapping is hard, different things can go wrong, *error handling* and *load order* just to name a few. The module aims to make it simple.\n\n`avvio` is fully *reentrant* and *graph-based*. You can load\ncomponents/plugins *within* plugins, and be still sure that things will\nhappen in the right order. At the end of the loading, your application will start.\n\n* [Install](#install)\n* [Example](#example)\n* [API](#api)\n* [Acknowledgments](#acknowledgments)\n* [License](#license)\n\n\u003ca name=\"install\"\u003e\u003c/a\u003e\n## Install\n\nTo install `avvio`, simply use npm:\n\n```\nnpm i avvio\n```\n\n\u003ca name=\"example\"\u003e\u003c/a\u003e\n## Example\n\nThe example below can be found [here][example] and run using `node example.js`.\nIt demonstrates how to use `avvio` to load functions/plugins in order.\n\n\n```js\n'use strict'\n\nconst app = require('avvio')()\n\napp\n  .use(first, { hello: 'world' })\n  .after((err, cb) =\u003e {\n    console.log('after first and second')\n    cb()\n  })\n\napp.use(third)\n\napp.ready(function (err) {\n  // the error must be handled somehow\n  if (err) {\n    throw err\n  }\n  console.log('application booted!')\n})\n\nfunction first (instance, opts, cb) {\n  console.log('first loaded', opts)\n  instance.use(second)\n  cb()\n}\n\nfunction second (instance, opts, cb) {\n  console.log('second loaded')\n  process.nextTick(cb)\n}\n\n// async/await or Promise support\nasync function third (instance, opts) {\n  console.log('third loaded')\n}\n```\n\n\u003ca name=\"api\"\u003e\u003c/a\u003e\n## API\n\n  * \u003ca href=\"#constructor\"\u003e\u003ccode\u003e\u003cb\u003eavvio()\u003c/b\u003e\u003c/code\u003e\u003c/a\u003e\n  * \u003ca href=\"#use\"\u003e\u003ccode\u003einstance.\u003cb\u003euse()\u003c/b\u003e\u003c/code\u003e\u003c/a\u003e\n  * \u003ca href=\"#after\"\u003e\u003ccode\u003einstance.\u003cb\u003eafter()\u003c/b\u003e\u003c/code\u003e\u003c/a\u003e\n  * \u003ca href=\"#await-after\"\u003e\u003ccode\u003eawait instance.\u003cb\u003eafter()\u003c/b\u003e\u003c/code\u003e\u003c/a\u003e\n  * \u003ca href=\"#ready\"\u003e\u003ccode\u003einstance.\u003cb\u003eready()\u003c/b\u003e\u003c/code\u003e\u003c/a\u003e\n  * \u003ca href=\"#start\"\u003e\u003ccode\u003einstance.\u003cb\u003estart()\u003c/b\u003e\u003c/code\u003e\u003c/a\u003e\n  * \u003ca href=\"#override\"\u003e\u003ccode\u003einstance.\u003cb\u003eoverride()\u003c/b\u003e\u003c/code\u003e\u003c/a\u003e\n  * \u003ca href=\"#onClose\"\u003e\u003ccode\u003einstance.\u003cb\u003eonClose()\u003c/b\u003e\u003c/code\u003e\u003c/a\u003e\n  * \u003ca href=\"#close\"\u003e\u003ccode\u003einstance.\u003cb\u003eclose()\u003c/b\u003e\u003c/code\u003e\u003c/a\u003e\n  * \u003ca href=\"#toJSON\"\u003e\u003ccode\u003eavvio.\u003cb\u003etoJSON()\u003c/b\u003e\u003c/code\u003e\u003c/a\u003e\n  * \u003ca href=\"#prettyPrint\"\u003e\u003ccode\u003eavvio.\u003cb\u003eprettyPrint()\u003c/b\u003e\u003c/code\u003e\u003c/a\u003e\n\n-------------------------------------------------------\n\u003ca name=\"constructor\"\u003e\u003c/a\u003e\n\n### avvio([instance], [options], [started])\n\nStarts the avvio sequence.\nAs the name suggests, `instance` is the object representing your application.\nAvvio will add the functions `use`, `after`, and `ready` to the instance.\n\n```js\nconst server = {}\n\nrequire('avvio')(server)\n\nserver.use(function first (s, opts, cb) {\n  // s is the same of server\n  s.use(function second (s, opts, cb) {\n    cb()\n  })\n  cb()\n}).after(function (err, cb) {\n  // after first and second are finished\n  cb()\n})\n```\n\nOptions:\n\n* `expose`: a key/value property to change how `use`, `after`, and `ready` are exposed.\n* `autostart`: do not start loading plugins automatically, but wait for\n  a call to [`.start()`](#start)  or [`.ready()`](#ready).\n* `timeout`: the number of milliseconds to wait for a plugin to load after which\n  it will error with code `ERR_AVVIO_PLUGIN_TIMEOUT`. Default\n  `0` (disabled).\n\nEvents:\n\n* `'start'`  when the application starts\n* `'preReady'` fired before the ready queue is run\n\nThe `avvio` function can also be used as a\nconstructor to inherit from.\n```js\nfunction Server () {}\nconst app = require('avvio')(new Server())\n\napp.use(function (s, opts, done) {\n  // your code\n  done()\n})\n\napp.on('start', () =\u003e {\n  // you app can start\n})\n```\n\n-------------------------------------------------------\n\u003ca name=\"use\"\u003e\u003c/a\u003e\n\n### app.use(func, [optsOrFunc]) =\u003e Thenable\n\nLoads one or more functions asynchronously.\n\nThe function **must** have the signature: `instance, options, done`\n\nPlugin example:\n```js\nfunction plugin (server, opts, done) {\n  done()\n}\n\napp.use(plugin)\n```\n`done` should be called only once, when your plugin is ready to go.  Additional calls to `done` are ignored.\n\nIf your plugin is ready to go immediately after the function is evaluated, you can omit `done` from the signature.\n\nIf the function returns a `Promise` (i.e. `async`), the above function signature is not required.\n\n`use` returns a thenable wrapped instance on which `use` is called, to support a chainable API that can also be awaited.\n\nThis way, async/await is also supported and `use` can be awaited instead of using `after`.\n\nExample using `after`:\n\n```js\nasync function main () {\n  console.log('begin')\n  app.use(async function (server, opts) {\n    await sleep(10)\n    console.log('this first')\n  })\n  app.after(async (err) =\u003e {\n    if (err) throw err\n    console.log('then this')\n  })\n  await app.ready()\n  console.log('ready')\n}\nmain().catch((err) =\u003e console.error(err))\n```\n\nExample using `await after`:\n\n\n```js\nasync function main () {\n  console.log('begin')\n  app.use(async function (server, opts) {\n    await sleep(10)\n    console.log('this first')\n  })\n  await app.after()\n  console.log('then this')\n  await app.ready()\n  console.log('ready')\n}\nmain().catch((err) =\u003e console.error(err))\n```\n\nExample using `await use`:\n\n```js\nasync function main () {\n  console.log('begin')\n  await app.use(async function (server, opts) {\n    await sleep(10)\n    console.log('this first')\n  })\n  console.log('then this')\n  await app.ready()\n  console.log('ready')\n}\nmain().catch((err) =\u003e console.error(err))\n```\n\nA function that returns the options argument instead of an object is supported as well:\n\n```js\nfunction first (server, opts, done) {\n  server.foo = 'bar'\n  done()\n}\n\nfunction second (server, opts, done) {\n  console.log(opts.foo === 'bar') // Evaluates to true\n  done()\n}\n\n/**\n * If the options argument is a function, it has access to the parent\n * instance via the first positional variable\n */\nconst func = parent =\u003e {\n  return {\n    foo: parent.foo\n  }\n}\n\napp.use(first)\napp.use(second, func)\n```\n\nThis is useful in cases where an injected variable from a plugin needs to be made available to another.\n\nIt is also possible to use [esm](https://nodejs.org/api/esm.html) with `import('./file.mjs')`:\n\n```js\nimport boot from 'avvio'\n\nconst app = boot()\napp.use(import('./fixtures/esm.mjs'))\n```\n\n-------------------------------------------------------\n\u003ca name=\"error-handling\"\u003e\u003c/a\u003e\n#### Error handling\n\nTo handle errors in the loading plugins, you must use the\n`.ready()` method, like so:\n\n```js\napp.use(function (instance, opts, done) {\n  done(new Error('error'))\n}, opts)\n\napp.ready(function (err) {\n  if (err) throw err\n})\n```\n\nWhen an error happens, the loading of plugins will stop until there is\nan [`after`](#after) callback specified. Otherwise, it will be handled\nin [`ready`](#ready).\n\n-------------------------------------------------------\n\u003ca name=\"after\"\u003e\u003c/a\u003e\n\n### app.after(func(error, [context], [done]))\n\nCalls a function after all the previously defined plugins are loaded, including\nall their dependencies. The `'start'` event is not emitted yet.\n\nNote: `await after` can be used as an awaitable alternative to `after(func)`, or `await use` can be also as a shorthand for `use(plugin); await after()`.\n\nThe callback changes based on the parameters you give:\n1. If no parameter is given to the callback and there is an error, that error will be passed to the next error handler.\n2. If one parameter is given to the callback, that parameter will be the `error` object.\n3. If two parameters are given to the callback, the first will be the `error` object, the second will be the `done` callback.\n4. If three parameters are given to the callback, the first will be the `error` object, the second will be the top-level `context`, and the third the `done` callback.\n\nIn the \"no parameter\" and \"one parameter\" variants, the callback can return a `Promise`.\n\n```js\nconst server = {}\nconst app = require('avvio')(server)\n\n...\n// after with one parameter\napp.after(function (err) {\n  if (err) throw err\n})\n\n// after with two parameter\napp.after(function (err, done) {\n  if (err) throw err\n  done()\n})\n\n// after with three parameters\napp.after(function (err, context, done) {\n  if (err) throw err\n  assert.equal(context, server)\n  done()\n})\n\n// async after with one parameter\napp.after(async function (err) {\n  await sleep(10)\n  if (err) {\n    throw err\n  }\n})\n\n// async after with no parameter\napp.after(async function () {\n  await sleep(10)\n})\n```\n\n`done` must be called only once.\n\nIf called with a function, it returns the instance on which `after` is called, to support a chainable API.\n\n-------------------------------------------------------\n\u003ca name=\"await-after\"\u003e\u003c/a\u003e\n\n### await app.after() | app.after() =\u003e Promise\n\nCalling after with no function argument loads any plugins previously registered via `use` and returns a promise, which resolves when all plugins registered so far have loaded.\n\n```js\nasync function main () {\n  app.use(async function (server, opts) {\n    await sleep(10)\n    console.log('this first')\n  })\n  app.use(async function (server, opts) {\n    await sleep(10)\n    console.log('this second')\n  })\n  console.log('before after')\n  await app.after()\n  console.log('after after')\n  app.use(async function (server, opts) {\n    await sleep(10)\n    console.log('this third')\n  })\n  await app.ready()\n  console.log('ready')\n}\nmain().catch((err) =\u003e console.error(err))\n```\n\nUnlike `after` and `use`, `await after` is *not* chainable.\n\n-------------------------------------------------------\n\u003ca name=\"ready\"\u003e\u003c/a\u003e\n\n### app.ready([func(error, [context], [done])])\n\nCalls a function after all the plugins and `after` call are completed, but before `'start'` is emitted. `ready` callbacks are executed one at a time.\n\nThe callback changes based on the parameters you give:\n1. If no parameter is given to the callback and there is an error, that error will be passed to the next error handler.\n2. If one parameter is given to the callback, that parameter will be the `error` object.\n3. If two parameters are given to the callback, the first will be the `error` object, the second will be the `done` callback.\n4. If three parameters are given to the callback, the first will be the `error` object, the second will be the top-level `context` unless you have specified both server and override, in that case the `context` will be what the override returns, and the third the `done` callback.\n\nIf no callback is provided `ready` will return a Promise that is resolved or rejected once plugins and `after` calls are completed.  On success `context` is provided to the `.then` callback, if an error occurs it is provided to the `.catch` callback.\n\n```js\nconst server = {}\nconst app = require('avvio')(server)\n...\n// ready with one parameter\napp.ready(function (err) {\n  if (err) throw err\n})\n\n// ready with two parameter\napp.ready(function (err, done) {\n  if (err) throw err\n  done()\n})\n\n// ready with three parameters\napp.ready(function (err, context, done) {\n  if (err) throw err\n  assert.equal(context, server)\n  done()\n})\n\n// ready with Promise\napp.ready()\n  .then(() =\u003e console.log('Ready'))\n  .catch(err =\u003e {\n    console.error(err)\n    process.exit(1)\n  })\n\n// await ready from an async function.\nasync function main () [\n  try {\n    await app.ready()\n    console.log('Ready')\n  } catch(err) {\n    console.error(err)\n    process.exit(1)\n  }\n}\n```\n\n`done` must be called only once.\n\nThe callback form of this function has no return value.\n\nIf `autostart: false` is passed as an option, calling `.ready()`  will\nalso start the boot sequence.\n\n-------------------------------------------------------\n\u003ca name=\"start\"\u003e\u003c/a\u003e\n\n### app.start()\n\nStart the boot sequence, if it was not started yet.\nReturns the `app` instance.\n\n-------------------------------------------------------\n\u003ca name=\"override\"\u003e\u003c/a\u003e\n\n### app.override(server, plugin, options)\n\nAllows overriding the instance of the server for each loading plugin.\nIt allows the creation of an inheritance chain for the server instances.\nThe first parameter is the server instance and the second is the plugin function while the third is the options object that you give to use.\n\n```js\nconst assert = require('node:assert')\nconst server = { count: 0 }\nconst app = require('avvio')(server)\n\nconsole.log(app !== server, 'override must be set on the Avvio instance')\n\napp.override = function (s, fn, opts) {\n  // create a new instance with the\n  // server as the prototype\n  const res = Object.create(s)\n  res.count = res.count + 1\n\n  return res\n}\n\napp.use(function first (s1, opts, cb) {\n  assert(s1 !== server)\n  assert(Object.prototype.isPrototypeOf.call(server, s1))\n  assert(s1.count === 1)\n  s1.use(second)\n  cb()\n\n  function second (s2, opts, cb) {\n    assert(s2 !== s1)\n    assert(Object.prototype.isPrototypeOf.isPrototypeOf.call(s1, s2))\n    assert(s2.count === 2)\n    cb()\n  }\n})\n```\n-------------------------------------------------------\n\n\u003ca name=\"onClose\"\u003e\u003c/a\u003e\n### app.onClose(func([context], [done]))\n\nRegisters a new callback that will be fired once then `close` api is called.\n\nThe callback changes based on the parameters you give:\n1. If one parameter is given to the callback, that parameter will be the `context`.\n2. If zero or one parameter is given, the callback may return a promise\n3. If two parameters are given to the callback, the first will be the top-level `context` unless you have specified both server and override, in that case the `context` will be what the override returns, the second will be the `done` callback.\n\n```js\nconst server = {}\nconst app = require('avvio')(server)\n...\n// onClose with one parameter\napp.onClose(function (context) {\n  // ...\n})\n\n// onClose with one parameter, returning a promise\napp.onClose(function (context) {\n  return new Promise((resolve, reject) =\u003e {\n    // ...\n  })\n})\n\n// async onClose with one parameter\napp.onClose(async function (context) {\n  // ...\n  await ...\n})\n\n\n// onClose with two parameter\napp.onClose(function (context, done) {\n  // ...\n  done()\n})\n```\n\nIf the callback returns a promise, the next onClose callback and the close callback will not run until the promise is either resolved or rejected.\n\n`done` must be called only once.\nReturns the instance on which `onClose` is called, to support a chainable API.\n\n-------------------------------------------------------\n\n\u003ca name=\"close\"\u003e\u003c/a\u003e\n### app.close(func(error, [context], [done]))\n\nStarts the shutdown procedure, the callback is called once all the registered callbacks with `onClose` have been executed.\n\nThe callback changes based on the parameters you give:\n1. If one parameter is given to the callback, that parameter will be the `error` object.\n2. If two parameters are given to the callback, the first will be the `error` object, the second will be the `done` callback.\n3. If three parameters are given to the callback, the first will be the `error` object, the second will be the top-level `context` unless you have specified both server and override, in that case the `context` will be what the override returns, and the third the `done` callback.\n\nIf no callback is provided `close` will return a Promise.\n\n```js\nconst server = {}\nconst app = require('avvio')(server)\n...\n// close with one parameter\napp.close(function (err) {\n  if (err) throw err\n})\n\n// close with two parameter\napp.close(function (err, done) {\n  if (err) throw err\n  done()\n})\n\n// close with three parameters\napp.close(function (err, context, done) {\n  if (err) throw err\n  assert.equal(context, server)\n  done()\n})\n\n// close with Promise\napp.close()\n  .then(() =\u003e console.log('Closed'))\n  .catch(err =\u003e {\n    console.error(err)\n    process.exit(1)\n  })\n\n```\n\n`done` must be called only once.\n\n-------------------------------------------------------\n\n\u003ca name=\"toJSON\"\u003e\u003c/a\u003e\n\n### avvio.toJSON()\n\nReturn a JSON tree representing the state of the plugins and the loading time.\nCall it on `preReady` to get the complete tree.\n\n```js\nconst avvio = require('avvio')()\navvio.on('preReady', () =\u003e {\n  avvio.toJSON()\n})\n```\n\nThe output is like this:\n```json\n{\n  \"label\": \"root\",\n  \"start\": 1550245184665,\n  \"nodes\": [\n    {\n      \"parent\": \"root\",\n      \"start\": 1550245184665,\n      \"label\": \"first\",\n      \"nodes\": [\n        {\n          \"parent\": \"first\",\n          \"start\": 1550245184708,\n          \"label\": \"second\",\n          \"nodes\": [],\n          \"stop\": 1550245184709,\n          \"diff\": 1\n        }\n      ],\n      \"stop\": 1550245184709,\n      \"diff\": 44\n    },\n    {\n      \"parent\": \"root\",\n      \"start\": 1550245184709,\n      \"label\": \"third\",\n      \"nodes\": [],\n      \"stop\": 1550245184709,\n      \"diff\": 0\n    }\n  ],\n  \"stop\": 1550245184709,\n  \"diff\": 44\n}\n```\n\n-------------------------------------------------------\n\n\u003ca name=\"prettyPrint\"\u003e\u003c/a\u003e\n\n### avvio.prettyPrint()\n\nThis method will return a printable string with the tree returned by the `toJSON()` method.\n\n```js\nconst avvio = require('avvio')()\navvio.on('preReady', () =\u003e {\n  console.log(avvio.prettyPrint())\n})\n```\n\nThe output will be like:\n\n```\navvio 56 ms\n├── first 52 ms\n├── second 1 ms\n└── third 2 ms\n```\n\n-------------------------------------------------------\n\n## Acknowledgments\n\nThis project was kindly sponsored by [nearForm](https://nearform.com).\n\n## License\n\nCopyright Matteo Collina 2016-2020, Licensed under [MIT][].\n\n[MIT]: ./LICENSE\n[example]: ./examples/example.js\n","funding_links":["https://github.com/sponsors/fastify","https://opencollective.com/fastify"],"categories":["JavaScript","Packages"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastify%2Favvio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffastify%2Favvio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastify%2Favvio/lists"}