{"id":15821180,"url":"https://github.com/eomm/fastify-explorer","last_synced_at":"2025-09-12T15:32:05.150Z","repository":{"id":45801542,"uuid":"224404340","full_name":"Eomm/fastify-explorer","owner":"Eomm","description":"Explore your fastify's instances","archived":true,"fork":false,"pushed_at":"2024-08-14T13:00:28.000Z","size":19,"stargazers_count":5,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-26T19:49:10.707Z","etag":null,"topics":["encapsulation","fastify","fastify-plugin","hacktoberfest"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Eomm.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}},"created_at":"2019-11-27T10:24:39.000Z","updated_at":"2024-09-19T17:07:17.000Z","dependencies_parsed_at":"2022-07-17T01:46:17.517Z","dependency_job_id":"9f4baa33-174c-4840-9517-3de2e5ae2257","html_url":"https://github.com/Eomm/fastify-explorer","commit_stats":{"total_commits":7,"total_committers":2,"mean_commits":3.5,"dds":0.2857142857142857,"last_synced_commit":"43d5db790b8f2edfb01248f200996df62439cb7b"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/Eomm/fastify-explorer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eomm%2Ffastify-explorer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eomm%2Ffastify-explorer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eomm%2Ffastify-explorer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eomm%2Ffastify-explorer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Eomm","download_url":"https://codeload.github.com/Eomm/fastify-explorer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eomm%2Ffastify-explorer/sbom","scorecard":{"id":46187,"data":{"date":"2025-08-11","repo":{"name":"github.com/Eomm/fastify-explorer","commit":"13a59bc64cb3a76eef7a33ebb0da853cdde7ec34"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.7,"checks":[{"name":"Maintained","score":0,"reason":"project is archived","details":["Warn: Repository is archived."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/7 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/Eomm/fastify-explorer/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:33: update your workflow using https://app.stepsecurity.io/secureworkflow/Eomm/fastify-explorer/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:54: update your workflow using https://app.stepsecurity.io/secureworkflow/Eomm/fastify-explorer/ci.yml/main?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/ci.yml:39","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":9,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:17","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/ci.yml:51","Warn: no topLevel permission defined: .github/workflows/ci.yml:1"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 4 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-14T22:49:38.773Z","repository_id":45801542,"created_at":"2025-08-14T22:49:38.773Z","updated_at":"2025-08-14T22:49:38.773Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274831537,"owners_count":25357882,"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","status":"online","status_checked_at":"2025-09-12T02:00:09.324Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["encapsulation","fastify","fastify-plugin","hacktoberfest"],"created_at":"2024-10-05T07:20:48.561Z","updated_at":"2025-09-12T15:32:04.809Z","avatar_url":"https://github.com/Eomm.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fastify-explorer\n\n[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)\n[![ci](https://github.com/Eomm/fastify-explorer/actions/workflows/ci.yml/badge.svg)](https://github.com/Eomm/fastify-explorer/actions/workflows/ci.yml)\n\nExplore your fastify instances.\n\nIf you understand how to use this plugin, you will archive the higher knowledge in the fastify encapsulation mechanism ✨\n\n\u003e **Note**  \n\u003e To deep dive the fastify encapsulation, you may want to try the [fastify-overview](https://github.com/Eomm/fastify-overview) plugin as well.\n\n## Install\n\n```\nnpm install fastify-explorer\n```\n\n### Compatibility\n\n| Plugin version | Fastify version |\n| ------------- |:---------------:|\n| `^1.0.0` | `^2.0.0` |\n| `^2.0.0` | `^4.0.0` |\n\n\n## Usage\n\nThe plugin will store a pointer to the fastify instances you are interested in, created with the `.register` function that will have the `explorer` configuration.\n__This operation will break the encapsulation and you must be confident with the plugin system.__\n\nIf you want to understand better the Fastify plugin system, give a look to this [blog post](https://backend.cafe/the-complete-guide-to-the-fastify-plugin-system).\n\n```js\nconst Fastify = require('fastify')\nconst fastifyExplorer = require('fastify-explorer')\n\nconst routes = require('./my-routes')\n\nconst app = Fastify()\napp.register(fastifyExplorer, { optionKey: 'explorer' })\n\napp.register(routes, { explorer: { name: 'routes-explorer' } })\n```\n\nNow you can access the `routes-explorer` fastify instance with the `giveMe` function!\nSee the [API](#api) section for more details.\n\n### Options\n\n- `optionKey`: the key to use to register the plugin name. Default: `explorer`\n\n### Use case: testing\n\nLet me show how I develop this plugin:\n\nUsually, I need to read data from a DB, like mongodb, and if you want 100% coverage, you need to\ntest the `error` case that usually is archived mocking the data or even the db driver.\n\nSo I prefer to get the mongodb connection of my fastify server.. and close it to let it throws!\nThe encapsulation hides the registered plugins unless using this plugin 😈\n\nThis is only an example, but you can get whatever decorator is attached to all the fastify instances!\n**Read the code-comments to have a complete overview of this plugin**.\n\nMoroever, this plugin forces you to develop your application with a solid pattern. Let's see it:\n\n#### `application.js`: factory pattern\n\nThis is the main file of your app, here you must create the fastify server and register plugins and routes.\nRemember: don't call `.listen` but simply return your server!\n\nNote that this plugin must be the first one to be registered.\n\n\n```js\nconst Fastify = require('fastify')\nconst fastifyMongo = require('@fastify/mongodb')\nconst fastifyExplorer = require('fastify-explorer')\n\nconst routes = require('./my-routes')\n\nmodule.exports = function build (config, explorer) {\n  const fastify = Fastify(config.server)\n\n  // use it only for test. if you don't nothing bad happens, only waste of RAM\n  if (explorer === true) {\n    // the register must be the FIRST ONE\n    fastify.register(fastifyExplorer)\n  }\n\n  fastify.register(fastifyMongo, { url: config.mongoUrl })\n\n  // To activate the plugin, you need to add and `explorer` config in registration phase\n  // If you don't register the plugin, the parameters are just ignored\n  fastify.register(routes, { explorer: { name: 'routes-explorer' } })\n\n  return fastify\n}\n```\n\n#### `server.js`: launcher\n\nNow you can run your application with [`fastify-cli`](https://github.com/fastify/fastify-cli/) or with the following code.\nThis file is a dumb file.. so we don't need to test it!\n\n```js\nconst buildApp = require('./application')\nconst conf = require('./config.json') \nconst server = buildApp(conf)\n\nserver.listen(3000, (err) =\u003e {\n  if (err) {\n    console.log(err)\n    process.exit(1)\n  }\n})\n```\n\n#### Test\n\nFinally, we can test our code!\nNote how our test is like the launcher.\n\n```js\nconst { test } = require('tap')\n\nconst buildApp = require('./application')\nconst conf = require('./config-test.json') \nconst server = buildApp(conf)\n\ntest('call my route and fail', t =\u003e {\n  t.plan(4)\n  const fastify = buildApp(conf, true) // we pass TRUE only in test!\n\n  fastify.ready(err =\u003e {\n    t.error(err)\n\n    // this mongo instance would be unreachable because hidden in the encapsulated context\n    const mongoInsideFastify = fastify.giveMe('routes-explorer', 'mongo')\n\n    // let's close the connection, so our routes will break!\n    mongoInsideFastify.client.close()\n\n    fastify.inject('/my-route', (err, res) =\u003e {\n      t.error(err)\n      t.equals(res.statusCode, 501) // this is a customized http status code\n      t.deepEquals(res.json(), {}) // empty mongo :)\n    })\n  })\n})\n```\n\n\n## API\n\nThis plugin adds two decorators to the fastify instance:\n\n- `giveMe(instanceName: string[, decoratorName: string])`: return the fastify instance registered with given name in parameters `{ explorer: { name: 'routes-explorer' } }`\n- `registerPlugin(pluginFunction: function, pluginOpts: object, explorerOpts: string|object)`: register a plugin adding an encapsulation layer. It is only a shortcut to create new fastify contexts.\n\nYou can find an example for `.giveMe` in this document.\n\n### Why `registerPlugin`?\n\nThis plugin works only when you register an encapsulated context. The `fastify-plugin` system breaks the encapsulation.. so this plugin wouldn't work with normal plugins!\nIn other words, the `onRegister` hook is called only when **new** contexts are created, and the plugins don't create new contexts!\n\nHere to you and example:\n\n```js\napp.register(fastifyExplorer)\n  .after(() =\u003e {\n    // use the decorator to register mongo\n    app.registerPlugin(fastifyMongo, { url: '...' }, 'theMongo')\n  })\n```\n\nI don't like this usage because it will impact too much on how you write your `application.js` file.\n\n\n### Another important question\n\nSomebody could ask: why pass the `explorer` parameters in the route's registration and not in mongo in `application.js`?\n\nAs explained in the `registerPlugin`'s section, it is useless writing because it doesn't work:\n\n```js\nfastify.register(fastifyMongo, { url: config.mongoUrl }, { explorer: { name: 'mongo-code' } })\n```\n\nSo, I have configured the `explorer` parameters in the routes because that code will create a new context that would have access to the mongo instance!\nIt seems tricky, but I think it is right, because I have named the routes I want to break: I'm not interested to the plugins itself.\n\n\n## Conclusion\n\nIf you have read all this documentation, you are great and I hope you have understood better the encapsulation context and how to play with it.\n\nUseful links:\n\n- https://backend.cafe/the-complete-guide-to-the-fastify-plugin-system\n- https://stackoverflow.com/questions/61020394/what-is-the-exact-use-of-fastify-plugin/61054534#61054534\n- https://github.com/Eomm/fastify-overview#fastify-overview\n\n\n## Future\n\nI'm thinking how to test complex scenarios like this one, where you want to break only the first `findOne` call and not the second one.\n\n```js\nfastify.get('/', async (req, res) =\u003e {\n  try {\n    const hello = await fastify.mongo.findOne({ _id: 'an-id' })\n  } catch(err) {\n    mqtt.publish('woooooo')\n    const world = await fastify.mongo.findOne({ _id: 'an-id-2' })\n  }\n})\n```\n\n\n## License\n\nCopyright [Manuel Spigolon](https://github.com/Eomm), Licensed under [MIT](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feomm%2Ffastify-explorer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feomm%2Ffastify-explorer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feomm%2Ffastify-explorer/lists"}