├── .gitattributes ├── .github ├── dependabot.yml ├── stale.yml └── workflows │ └── ci.yml ├── .gitignore ├── .npmrc ├── LICENSE ├── README.md ├── eslint.config.js ├── index.js ├── package.json ├── test ├── .env └── fastify-env.test.js └── types ├── index.d.ts └── index.test-d.ts /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behavior to automatically convert line endings 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | open-pull-requests-limit: 10 8 | 9 | - package-ecosystem: "npm" 10 | directory: "/" 11 | schedule: 12 | interval: "monthly" 13 | open-pull-requests-limit: 10 14 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 15 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - "discussion" 8 | - "feature request" 9 | - "bug" 10 | - "help wanted" 11 | - "plugin suggestion" 12 | - "good first issue" 13 | # Label to use when marking an issue as stale 14 | staleLabel: stale 15 | # Comment to post when marking an issue as stale. Set to `false` to disable 16 | markComment: > 17 | This issue has been automatically marked as stale because it has not had 18 | recent activity. It will be closed if no further activity occurs. Thank you 19 | for your contributions. 20 | # Comment to post when closing a stale issue. Set to `false` to disable 21 | closeComment: false 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - next 8 | - 'v*' 9 | paths-ignore: 10 | - 'docs/**' 11 | - '*.md' 12 | pull_request: 13 | paths-ignore: 14 | - 'docs/**' 15 | - '*.md' 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | test: 22 | permissions: 23 | contents: write 24 | pull-requests: write 25 | uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5 26 | with: 27 | license-check: true 28 | lint: true 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | 132 | # Vim swap files 133 | *.swp 134 | 135 | # macOS files 136 | .DS_Store 137 | 138 | # Clinic 139 | .clinic 140 | 141 | # lock files 142 | bun.lockb 143 | package-lock.json 144 | pnpm-lock.yaml 145 | yarn.lock 146 | 147 | # editor files 148 | .vscode 149 | .idea 150 | 151 | #tap files 152 | .tap/ 153 | 154 | # test env variables file 155 | !test/.env 156 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Fastify 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @fastify/env 2 | 3 | [![CI](https://github.com/fastify/fastify-env/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/fastify-env/actions/workflows/ci.yml) 4 | [![NPM version](https://img.shields.io/npm/v/@fastify/env.svg?style=flat)](https://www.npmjs.com/package/@fastify/env) 5 | [![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard) 6 | 7 | Fastify plugin to check environment variables 8 | 9 | ## Install 10 | 11 | ``` 12 | npm i @fastify/env 13 | ``` 14 | 15 | ### Compatibility 16 | 17 | | Plugin version | Fastify version | 18 | | ---------------|-----------------| 19 | | `>=5.x` | `^5.x` | 20 | | `^4.x` | `^4.x` | 21 | | `>=2.x <4.x` | `^3.x` | 22 | | `>=0.x 2.x` | `^2.x` | 23 | | `>=0.x 2.x` | `^1.x` | 24 | 25 | 26 | Please note that if a Fastify version is out of support, then so are the corresponding versions of this plugin 27 | in the table above. 28 | See [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details. 29 | 30 | ## Usage 31 | 32 | ```js 33 | const fastify = require('fastify')() 34 | const fastifyEnv = require('@fastify/env') 35 | 36 | const schema = { 37 | type: 'object', 38 | required: [ 'PORT' ], 39 | properties: { 40 | PORT: { 41 | type: 'string', 42 | default: 3000 43 | } 44 | } 45 | } 46 | 47 | const options = { 48 | confKey: 'config', // optional, default: 'config' 49 | schema: schema, 50 | data: data // optional, default: process.env 51 | } 52 | 53 | fastify 54 | .register(fastifyEnv, options) 55 | .ready((err) => { 56 | if (err) console.error(err) 57 | 58 | console.log(fastify.config) // or fastify[options.confKey] 59 | console.log(fastify.getEnvs()) 60 | // output: { PORT: 3000 } 61 | }) 62 | ``` 63 | 64 | You can also use the function `getEnvs()` of the Request from within a handler function: 65 | ```js 66 | fastify.get('/', (request, reply) => { 67 | console.log(request.getEnvs()) 68 | // output: { PORT: 3000 } 69 | }) 70 | ``` 71 | Note that the `getEnvs` decorators will not be added if they already exist. 72 | 73 | This module is a wrapper around [env-schema](https://www.npmjs.com/package/env-schema). 74 | To read a `.env` file you must set `dotenv` in the options: 75 | 76 | ```js 77 | const options = { 78 | dotenv: true // will read .env in root folder 79 | } 80 | 81 | // or, pass config options available on dotenv module 82 | const options = { 83 | dotenv: { 84 | path: `${__dirname}/.env`, 85 | debug: true 86 | } 87 | } 88 | 89 | ``` 90 | ### Using @fastify/env to configure other plugins 91 | The `@fastify/env` plugin loads asynchronously. If you wish to use its values in a different plugin before the boot sequence, you need to make sure that: 92 | 1. `@fastify/env` is registered first. 93 | 2. Await the plugin registration or await after() 94 | 95 | ```js 96 | await fastify.register(fastifyEnv) 97 | // fastify.config can be used in here 98 | ``` 99 | 100 | OR 101 | ```js 102 | fastify.register(fastifyEnv) 103 | await fastify 104 | // fastify.config can be used in here 105 | ``` 106 | **NB** Support for additional properties in the schema is disabled for this plugin, with the `additionalProperties` flag set to `false` internally. 107 | 108 | ### Typescript 109 | To have typings for the fastify instance, you should either: 110 | 111 | - use the `declaration merging` technique to enhance the `FastifyInstance` type with the property and its keys you have defined in the options: 112 | 113 | ```typescript 114 | declare module 'fastify' { 115 | interface FastifyInstance { 116 | config: { // this should be the same as the confKey in options 117 | // specify your typing here 118 | FOO: string 119 | }; 120 | } 121 | } 122 | 123 | const fastify = Fastify() 124 | fastify.register(fastifyEnv) 125 | 126 | fastify.config.FOO // will be a string 127 | fastify.config.BAR // error: Property BAR does not exist on type { FOO: string } 128 | ``` 129 | 130 | - use the generic function `getEnvs()` to get the already typed object: 131 | 132 | ```typescript 133 | type Envs = { 134 | FOO: string 135 | } 136 | 137 | const fastify = Fastify() 138 | await fastify.register(fastifyEnv) 139 | 140 | const envs = fastify.getEnvs() // envs will be of type Envs 141 | 142 | envs.FOO // will be a string 143 | envs.BAR // error: Property BAR does not exist on type Envs 144 | ``` 145 | If this is the case it is suggested to use [json-schema-to-ts](https://github.com/ThomasAribart/json-schema-to-ts) to have the type always synchronized with the actual schema. 146 | 147 | ## Acknowledgments 148 | 149 | Kindly sponsored by [Mia Platform](https://www.mia-platform.eu/). 150 | 151 | ## License 152 | 153 | Licensed under [MIT](./LICENSE). 154 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = require('neostandard')({ 4 | ignores: require('neostandard').resolveIgnoresFromGitignore(), 5 | ts: true 6 | }) 7 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fp = require('fastify-plugin') 4 | const envSchema = require('env-schema') 5 | 6 | function fastifyEnv (fastify, opts, done) { 7 | try { 8 | const config = envSchema(opts) 9 | const confKey = opts.confKey || 'config' 10 | fastify.decorate(confKey, config) 11 | 12 | if (!fastify.hasDecorator('getEnvs')) { 13 | fastify.decorate('getEnvs', () => config) 14 | } 15 | if (!fastify.hasRequestDecorator('getEnvs')) { 16 | fastify.decorateRequest('getEnvs', () => config) 17 | } 18 | 19 | done() 20 | } catch (err) { 21 | done(err) 22 | } 23 | } 24 | 25 | module.exports = fp(fastifyEnv, { 26 | fastify: '5.x', 27 | name: '@fastify/env' 28 | }) 29 | module.exports.default = fastifyEnv 30 | module.exports.fastifyEnv = fastifyEnv 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fastify/env", 3 | "version": "5.0.2", 4 | "description": "Fastify plugin to check environment variables", 5 | "main": "index.js", 6 | "type": "commonjs", 7 | "types": "types/index.d.ts", 8 | "scripts": { 9 | "coverage": "cross-env VALUE_FROM_ENV=pippo c8 --reporter=html node --test", 10 | "lint": "eslint", 11 | "lint:fix": "eslint --fix", 12 | "test": "npm run test:unit && npm run test:typescript", 13 | "test:typescript": "tsd", 14 | "test:unit": "c8 --100 cross-env VALUE_FROM_ENV=pippo node --test" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/fastify/fastify-env.git" 19 | }, 20 | "keywords": [ 21 | "fastify" 22 | ], 23 | "author": "Tommaso Allevi - @allevo", 24 | "contributors": [ 25 | { 26 | "name": "James Sumners", 27 | "url": "https://james.sumners.info" 28 | }, 29 | { 30 | "name": "Manuel Spigolon", 31 | "email": "behemoth89@gmail.com" 32 | }, 33 | { 34 | "name": "Matteo Collina", 35 | "email": "hello@matteocollina.com" 36 | }, 37 | { 38 | "name": "Frazer Smith", 39 | "email": "frazer.dev@icloud.com", 40 | "url": "https://github.com/fdawgs" 41 | } 42 | ], 43 | "license": "MIT", 44 | "bugs": { 45 | "url": "https://github.com/fastify/fastify-env/issues" 46 | }, 47 | "homepage": "https://github.com/fastify/fastify-env#readme", 48 | "funding": [ 49 | { 50 | "type": "github", 51 | "url": "https://github.com/sponsors/fastify" 52 | }, 53 | { 54 | "type": "opencollective", 55 | "url": "https://opencollective.com/fastify" 56 | } 57 | ], 58 | "dependencies": { 59 | "env-schema": "^6.0.0", 60 | "fastify-plugin": "^5.0.0" 61 | }, 62 | "devDependencies": { 63 | "@fastify/pre-commit": "^2.1.0", 64 | "@types/node": "^22.0.0", 65 | "c8": "^10.1.2", 66 | "cross-env": "^7.0.3", 67 | "eslint": "^9.17.0", 68 | "fastify": "^5.0.0", 69 | "neostandard": "^0.12.0", 70 | "tsd": "^0.32.0" 71 | }, 72 | "pre-commit": [ 73 | "lint", 74 | "test" 75 | ], 76 | "tsd": { 77 | "directory": "test/types" 78 | }, 79 | "publishConfig": { 80 | "access": "public" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /test/.env: -------------------------------------------------------------------------------- 1 | VALUE_FROM_DOTENV=look ma 2 | -------------------------------------------------------------------------------- /test/fastify-env.test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const t = require('node:test') 4 | const path = require('node:path') 5 | const Fastify = require('fastify') 6 | const fastifyEnv = require('../index') 7 | 8 | async function makeTest (t, options, isOk, confExpected, errorMessage) { 9 | t.plan(isOk ? 2 : 1) 10 | 11 | const fastify = Fastify() 12 | try { 13 | await fastify.register(fastifyEnv, options) 14 | await fastify.ready() 15 | 16 | if (isOk) { 17 | t.assert.ifError(null) 18 | t.assert.deepStrictEqual(fastify.config, confExpected) 19 | } 20 | } catch (err) { 21 | if (!isOk) { 22 | t.assert.deepStrictEqual(err.message, errorMessage) 23 | } 24 | } 25 | } 26 | 27 | const tests = [ 28 | { 29 | name: 'empty ok', 30 | schema: { type: 'object' }, 31 | data: { }, 32 | isOk: true, 33 | confExpected: {} 34 | }, 35 | { 36 | name: 'simple object - ok', 37 | schema: { 38 | type: 'object', 39 | properties: { 40 | PORT: { 41 | type: 'string' 42 | } 43 | } 44 | }, 45 | data: { 46 | PORT: '44' 47 | }, 48 | isOk: true, 49 | confExpected: { 50 | PORT: '44' 51 | } 52 | }, 53 | { 54 | name: 'simple object - ok - coerce value', 55 | schema: { 56 | type: 'object', 57 | properties: { 58 | PORT: { 59 | type: 'integer' 60 | } 61 | } 62 | }, 63 | data: { 64 | PORT: '44' 65 | }, 66 | isOk: true, 67 | confExpected: { 68 | PORT: 44 69 | } 70 | }, 71 | { 72 | name: 'simple object - ok - remove additional properties', 73 | schema: { 74 | type: 'object', 75 | properties: { 76 | PORT: { 77 | type: 'integer' 78 | } 79 | } 80 | }, 81 | data: { 82 | PORT: '44', 83 | ANOTHER_PORT: '55' 84 | }, 85 | isOk: true, 86 | confExpected: { 87 | PORT: 44 88 | } 89 | }, 90 | { 91 | name: 'simple object - ok - use default', 92 | schema: { 93 | type: 'object', 94 | properties: { 95 | PORT: { 96 | type: 'integer', 97 | default: 5555 98 | } 99 | } 100 | }, 101 | data: { }, 102 | isOk: true, 103 | confExpected: { 104 | PORT: 5555 105 | } 106 | }, 107 | { 108 | name: 'simple object - ok - required + default', 109 | schema: { 110 | type: 'object', 111 | required: ['PORT'], 112 | properties: { 113 | PORT: { 114 | type: 'integer', 115 | default: 6666 116 | } 117 | } 118 | }, 119 | data: { }, 120 | isOk: true, 121 | confExpected: { 122 | PORT: 6666 123 | } 124 | }, 125 | { 126 | name: 'simple object - ok - allow array', 127 | schema: { 128 | type: 'object', 129 | required: ['PORT'], 130 | properties: { 131 | PORT: { 132 | type: 'integer', 133 | default: 6666 134 | } 135 | } 136 | }, 137 | data: [{ }], 138 | isOk: true, 139 | confExpected: { 140 | PORT: 6666 141 | } 142 | }, 143 | { 144 | name: 'simple object - ok - merge multiple object + env', 145 | schema: { 146 | type: 'object', 147 | required: ['PORT', 'MONGODB_URL'], 148 | properties: { 149 | PORT: { 150 | type: 'integer', 151 | default: 6666 152 | }, 153 | MONGODB_URL: { 154 | type: 'string' 155 | }, 156 | VALUE_FROM_ENV: { 157 | type: 'string' 158 | } 159 | } 160 | }, 161 | data: [{ PORT: 3333 }, { MONGODB_URL: 'mongodb://localhost/pippo' }], 162 | isOk: true, 163 | confExpected: { 164 | PORT: 3333, 165 | MONGODB_URL: 'mongodb://localhost/pippo', 166 | VALUE_FROM_ENV: 'pippo' 167 | } 168 | }, 169 | { 170 | name: 'simple object - ok - load only from env', 171 | schema: { 172 | type: 'object', 173 | required: ['VALUE_FROM_ENV'], 174 | properties: { 175 | VALUE_FROM_ENV: { 176 | type: 'string' 177 | } 178 | } 179 | }, 180 | data: undefined, 181 | isOk: true, 182 | confExpected: { 183 | VALUE_FROM_ENV: 'pippo' 184 | } 185 | }, 186 | { 187 | name: 'simple object - ok - opts override environment', 188 | schema: { 189 | type: 'object', 190 | required: ['VALUE_FROM_ENV'], 191 | properties: { 192 | VALUE_FROM_ENV: { 193 | type: 'string' 194 | } 195 | } 196 | }, 197 | data: { VALUE_FROM_ENV: 'pluto' }, 198 | isOk: true, 199 | confExpected: { 200 | VALUE_FROM_ENV: 'pluto' 201 | } 202 | }, 203 | { 204 | name: 'simple object - ok - load only from .env', 205 | schema: { 206 | type: 'object', 207 | required: ['VALUE_FROM_DOTENV'], 208 | properties: { 209 | VALUE_FROM_DOTENV: { 210 | type: 'string' 211 | } 212 | } 213 | }, 214 | data: undefined, 215 | isOk: true, 216 | dotenv: { path: path.join(__dirname, '.env') }, 217 | confExpected: { 218 | VALUE_FROM_DOTENV: 'look ma' 219 | } 220 | }, 221 | { 222 | name: 'simple object - KO', 223 | schema: { 224 | type: 'object', 225 | required: ['PORT'], 226 | properties: { 227 | PORT: { 228 | type: 'integer' 229 | } 230 | } 231 | }, 232 | data: { }, 233 | isOk: false, 234 | errorMessage: 'env must have required property \'PORT\'' 235 | }, 236 | { 237 | name: 'simple object - invalid data', 238 | schema: { 239 | type: 'object', 240 | required: ['PORT'], 241 | properties: { 242 | PORT: { 243 | type: 'integer' 244 | } 245 | } 246 | }, 247 | data: [], 248 | isOk: false, 249 | errorMessage: 'opts/data must NOT have fewer than 1 items, opts/data must be object, opts/data must match exactly one schema in oneOf' 250 | } 251 | ] 252 | 253 | for (const testConf of tests) { 254 | t.test(testConf.name, async t => { 255 | const options = { 256 | schema: testConf.schema, 257 | data: testConf.data, 258 | dotenv: testConf.dotenv, 259 | dotenvConfig: testConf.dotenvConfig 260 | } 261 | 262 | await makeTest(t, options, testConf.isOk, testConf.confExpected, testConf.errorMessage) 263 | }) 264 | } 265 | 266 | t.test('should use custom config key name', async (t) => { 267 | t.plan(1) 268 | const schema = { 269 | type: 'object', 270 | required: ['PORT'], 271 | properties: { 272 | PORT: { 273 | type: 'integer', 274 | default: 6666 275 | } 276 | } 277 | } 278 | 279 | const fastify = Fastify() 280 | await fastify.register(fastifyEnv, { 281 | schema, 282 | confKey: 'customConfigKeyName' 283 | }) 284 | await fastify.ready() 285 | t.assert.deepStrictEqual(fastify.customConfigKeyName, { PORT: 6666 }) 286 | }) 287 | 288 | t.test('should use function `getEnvs` to retrieve the envs object', async t => { 289 | t.plan(2) 290 | 291 | const schema = { 292 | type: 'object', 293 | properties: { 294 | PORT: { type: 'integer', default: 6666 } 295 | } 296 | } 297 | 298 | const fastify = Fastify() 299 | 300 | let requestEnvs 301 | fastify.get('/', (request) => { 302 | requestEnvs = request.getEnvs() 303 | return 'ok' 304 | }) 305 | 306 | await fastify.register(fastifyEnv, { 307 | schema 308 | }) 309 | 310 | await fastify.inject({ 311 | method: 'GET', 312 | url: '/' 313 | }) 314 | 315 | t.assert.deepStrictEqual(requestEnvs, { PORT: 6666 }) 316 | t.assert.deepStrictEqual(fastify.getEnvs(), { PORT: 6666 }) 317 | }) 318 | t.test('should skip the getEnvs decorators if there is already one with the same name', async t => { 319 | t.plan(2) 320 | 321 | const schema = { 322 | type: 'object', 323 | properties: { 324 | PORT: { type: 'integer', default: 6666 } 325 | } 326 | } 327 | 328 | const fastify = Fastify() 329 | fastify.decorate('getEnvs', () => { return 'another_value' }) 330 | fastify.decorateRequest('getEnvs', () => { return 'another_value' }) 331 | 332 | let requestEnvs 333 | fastify.get('/', (request) => { 334 | requestEnvs = request.getEnvs() 335 | return 'ok' 336 | }) 337 | 338 | await fastify.register(fastifyEnv, { 339 | schema 340 | }) 341 | 342 | await fastify.inject({ 343 | method: 'GET', 344 | url: '/' 345 | }) 346 | 347 | t.assert.deepStrictEqual(requestEnvs, 'another_value') 348 | t.assert.deepStrictEqual(fastify.getEnvs(), 'another_value') 349 | }) 350 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import { EnvSchemaOpt } from 'env-schema' 2 | import { FastifyPluginCallback } from 'fastify' 3 | 4 | declare module 'fastify' { 5 | export interface FastifyInstance { 6 | // Returns the environment variables object. 7 | getEnvs(): E, 8 | } 9 | 10 | export interface FastifyRequest { 11 | // Returns the environment variables object. 12 | getEnvs(): E, 13 | } 14 | } 15 | 16 | type FastifyEnv = FastifyPluginCallback 17 | 18 | declare namespace fastifyEnv { 19 | export interface FastifyEnvOptions extends EnvSchemaOpt { 20 | confKey?: string 21 | } 22 | 23 | /** 24 | * @deprecated Use FastifyEnvOptions instead 25 | */ 26 | export type fastifyEnvOpt = FastifyEnvOptions 27 | 28 | export const fastifyEnv: FastifyEnv 29 | export { fastifyEnv as default } 30 | } 31 | 32 | declare function fastifyEnv (...params: Parameters): ReturnType 33 | export = fastifyEnv 34 | -------------------------------------------------------------------------------- /types/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import Fastify, { FastifyInstance, FastifyRequest } from 'fastify' 2 | import { expectDeprecated, expectType } from 'tsd' 3 | import fastifyEnv, { FastifyEnvOptions, fastifyEnvOpt } from '..' 4 | 5 | const fastify = Fastify() 6 | 7 | fastify.register(fastifyEnv, { confKey: 'test' }) 8 | 9 | fastify.register(fastifyEnv) 10 | fastify.register(fastifyEnv, {}) 11 | fastify.register(fastifyEnv, { 12 | schema: {}, 13 | }) 14 | fastify.register(fastifyEnv, { 15 | data: {}, 16 | }) 17 | fastify.register(fastifyEnv, { 18 | data: [{}], 19 | }) 20 | fastify.register(fastifyEnv, { 21 | env: true, 22 | }) 23 | fastify.register(fastifyEnv, { 24 | dotenv: true, 25 | }) 26 | fastify.register(fastifyEnv, { 27 | dotenv: {}, 28 | }) 29 | fastify.register(fastifyEnv, { 30 | confKey: 'config' 31 | }) 32 | 33 | expectDeprecated({} as fastifyEnvOpt) 34 | expectType({} as fastifyEnvOpt) 35 | 36 | type Envs = { 37 | FOO: string 38 | } 39 | declare const instance: FastifyInstance 40 | expectType(instance.getEnvs()) 41 | declare const request: FastifyRequest 42 | expectType(request.getEnvs()) 43 | --------------------------------------------------------------------------------