This commit is contained in:
Tutur33
2023-11-24 22:35:41 +01:00
parent 3c0b507a93
commit 7644b2a0f7
45165 changed files with 4803356 additions and 3 deletions
+59
View File
@@ -0,0 +1,59 @@
/// <reference path="../../adonis-typings/env.d.ts" />
import { DotenvParseOutput } from 'dotenv';
import { EnvContract, ValidateFn } from '@ioc:Adonis/Core/Env';
/**
* The ENV module enables the use of environment variables by parsing dotfiles syntax
* and updates the `process.env` object in Node.js.
*
* AdonisJs automatically reads and passes the contents of `.env` file to this class.
*/
export declare class Env implements EnvContract {
private valuesToProcess;
/**
* A boolean to know if the values have been processed or
* not
*/
private hasProcessedValues;
/**
* A cache of env values
*/
private envCache;
/**
* The schema to be used for validating and casting environment
* variables
*/
private validationSchema;
constructor(valuesToProcess: {
values: DotenvParseOutput;
overwriteExisting: boolean;
}[]);
/**
* Reference to the underlying schema
*/
schema: import("@ioc:Adonis/Core/Env").EnvSchema;
/**
* Process parsed env variables. The values will be validated
* against the validation schema
*/
process(): void;
/**
* Register the validation schema
*/
rules(schema: {
[key: string]: ValidateFn<unknown>;
}): any;
/**
* Returns the environment variable value. First the cached
* values are preferred. When missing, the value from
* "process.env" is used
*/
get(key: string, defaultValue?: any): any;
/**
* Set key-value pair. The value will be validated using
* the validation rule if exists.
*
* The original value is also updated on the `process.env`
* object
*/
set(key: string, value: any): void;
}
+140
View File
@@ -0,0 +1,140 @@
"use strict";
/*
* @adonisjs/env
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Env = void 0;
const Schema_1 = require("../Schema");
/**
* The ENV module enables the use of environment variables by parsing dotfiles syntax
* and updates the `process.env` object in Node.js.
*
* AdonisJs automatically reads and passes the contents of `.env` file to this class.
*/
class Env {
constructor(valuesToProcess) {
this.valuesToProcess = valuesToProcess;
/**
* A boolean to know if the values have been processed or
* not
*/
this.hasProcessedValues = false;
/**
* A cache of env values
*/
this.envCache = {};
/**
* The schema to be used for validating and casting environment
* variables
*/
this.validationSchema = {};
/**
* Reference to the underlying schema
*/
this.schema = Schema_1.schema;
}
/**
* Process parsed env variables. The values will be validated
* against the validation schema
*/
process() {
/**
* Avoid re-processing the same values over and over
* again
*/
if (this.hasProcessedValues) {
return;
}
this.hasProcessedValues = true;
/**
* Loop over the parsed object and set the value
* on the process.env and the local cache.
*
* At this stage we process the values like a regular env parser with
* no validation taking place
*/
this.valuesToProcess.forEach(({ values, overwriteExisting }) => {
Object.keys(values).forEach((key) => {
/**
* Use existing value when it already exists in process.env object
* and [this.overwriteExisting] is set to false
*/
const existingValue = process.env[key];
if (existingValue && !overwriteExisting) {
this.envCache[key] = existingValue;
return;
}
/**
* Otherwise set the value on "process.env"
*/
this.envCache[key] = values[key];
process.env[key] = values[key];
});
});
/**
* Release parsed values, since we don't need it anymore
*/
this.valuesToProcess = [];
/**
* Perform validations by reading the environment variables
*/
Object.keys(this.validationSchema).forEach((key) => {
this.envCache[key] = this.validationSchema[key](key, this.get(key));
});
}
/**
* Register the validation schema
*/
rules(schema) {
this.validationSchema = schema;
return {};
}
/**
* Returns the environment variable value. First the cached
* values are preferred. When missing, the value from
* "process.env" is used
*/
get(key, defaultValue) {
/**
* Return cached value
*/
if (this.envCache[key] !== undefined) {
return this.envCache[key];
}
/**
* Get value from process.env and update the cache
*/
const envValue = process.env[key];
if (envValue) {
this.envCache[key] = envValue;
return envValue;
}
/**
* Return default value when unable to lookup any other value
*/
return defaultValue;
}
/**
* Set key-value pair. The value will be validated using
* the validation rule if exists.
*
* The original value is also updated on the `process.env`
* object
*/
set(key, value) {
const validationFn = this.validationSchema[key];
if (validationFn) {
this.envCache[key] = validationFn(key, value);
}
else {
this.envCache[key] = value;
}
process.env[key] = value;
}
}
exports.Env = Env;
+54
View File
@@ -0,0 +1,54 @@
/**
* Env parser parses the environment variables from a string formatted
* as a key-value pair seperated using an `=`. For example:
*
* ```
* PORT=3333
* HOST=127.0.0.1
* ```
*
* The variables can reference other environment variables as well using `$`.
* For example:
*
* ```
* PORT=3333
* REDIS_PORT=$PORT
* ```
*
* The variables using characters other than letters can use wrap variables inside
* a curly brace.
*
* ```
* APP-PORT=3333
* REDIS_PORT=${APP-PORT}
* ```
*/
export declare class EnvParser {
private preferExistingEnvVariables;
constructor(preferExistingEnvVariables?: boolean);
/**
* Returns value for a given key from the environment variables. Also
* the current parsed object is used to pull the reference.
*/
private getValue;
/**
* Interpolating the token wrapped inside the mustache
* braces.
*/
private interpolateMustache;
/**
* Interpolating the variable reference starting with a
* `$`. We only capture numbers,letter and underscore.
* For other characters, one can use the mustache
* braces.
*/
private interpolateVariable;
/**
* Interpolates the referenced values
*/
private interpolate;
/**
* Parse the env string to an object of environment variables.
*/
parse(envString: string): {};
}
+172
View File
@@ -0,0 +1,172 @@
"use strict";
/*
* @adonisjs/env
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EnvParser = void 0;
const dotenv_1 = __importDefault(require("dotenv"));
/**
* Env parser parses the environment variables from a string formatted
* as a key-value pair seperated using an `=`. For example:
*
* ```
* PORT=3333
* HOST=127.0.0.1
* ```
*
* The variables can reference other environment variables as well using `$`.
* For example:
*
* ```
* PORT=3333
* REDIS_PORT=$PORT
* ```
*
* The variables using characters other than letters can use wrap variables inside
* a curly brace.
*
* ```
* APP-PORT=3333
* REDIS_PORT=${APP-PORT}
* ```
*/
class EnvParser {
constructor(preferExistingEnvVariables = true) {
this.preferExistingEnvVariables = preferExistingEnvVariables;
}
/**
* Returns value for a given key from the environment variables. Also
* the current parsed object is used to pull the reference.
*/
getValue(key, parsed) {
/**
* When existing env variables are preferred, then we lookup the
* value inside `process.env` first.
*/
if (this.preferExistingEnvVariables) {
if (process.env[key]) {
return process.env[key];
}
if (parsed[key]) {
return this.interpolate(parsed[key], parsed);
}
return '';
}
/**
* Otherwise we lookup the value inside the parsed object
* first
*/
if (parsed[key]) {
return this.interpolate(parsed[key], parsed);
}
if (process.env[key]) {
return process.env[key];
}
return '';
}
/**
* Interpolating the token wrapped inside the mustache
* braces.
*/
interpolateMustache(token, parsed) {
/**
* Finding the closing brace. If closing brace is missing, we
* consider the block as a normal string
*/
const closingBrace = token.indexOf('}');
if (closingBrace === -1) {
return token;
}
/**
* Then we pull everything until the closing brace, except
* the opening brace and trim off all white spaces.
*/
const varReference = token.slice(1, closingBrace).trim();
/**
* Getting the value of the reference inside the braces
*/
return `${this.getValue(varReference, parsed)}${token.slice(closingBrace + 1)}`;
}
/**
* Interpolating the variable reference starting with a
* `$`. We only capture numbers,letter and underscore.
* For other characters, one can use the mustache
* braces.
*/
interpolateVariable(token, parsed) {
return token.replace(/[a-zA-Z0-9_]+/, (key) => {
return this.getValue(key, parsed);
});
}
/**
* Interpolates the referenced values
*/
interpolate(value, parsed) {
const tokens = value.split('$');
let newValue = '';
let skipNextToken = true;
tokens.forEach((token) => {
/**
* If the value is an escaped sequence, then we replace it
* with a `$` and then skip the next token.
*/
if (token === '\\') {
newValue += '$';
skipNextToken = true;
return;
}
/**
* Use the value as it is when "skipNextToken" is set to true.
*/
if (skipNextToken) {
/**
* Replace the ending escape sequence with a $
*/
newValue += token.replace(/\\$/, '$');
/**
* and then skip the next token if it ends with escape sequence
*/
if (token.endsWith('\\')) {
return;
}
}
else {
/**
* Handle mustache block
*/
if (token.startsWith('{')) {
newValue += this.interpolateMustache(token, parsed);
return;
}
/**
* Process all words as variable
*/
newValue += this.interpolateVariable(token, parsed);
}
/**
* Process next token
*/
skipNextToken = false;
});
return newValue;
}
/**
* Parse the env string to an object of environment variables.
*/
parse(envString) {
const envCollection = dotenv_1.default.parse(envString.trim());
return Object.keys(envCollection).reduce((result, key) => {
result[key] = this.interpolate(envCollection[key], envCollection);
return result;
}, {});
}
}
exports.EnvParser = EnvParser;
+10
View File
@@ -0,0 +1,10 @@
import { SchemaFnOptions } from '@ioc:Adonis/Core/Env';
/**
* Enforces the value to be of type boolean. Also casts
* string representation of a boolean to a boolean
* type
*/
export declare function boolean(options?: SchemaFnOptions): (key: string, value?: string | undefined) => boolean;
export declare namespace boolean {
var optional: (options?: SchemaFnOptions | undefined) => (key: string, value?: string | undefined) => boolean | undefined;
}
+49
View File
@@ -0,0 +1,49 @@
"use strict";
/*
* @adonisjs/env
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.boolean = void 0;
const utils_1 = require("@poppinss/utils");
const helpers_1 = require("./helpers");
/**
* Casts a string value to a boolean
*/
function castToBoolean(key, value, message) {
if (helpers_1.BOOLEAN_POSITIVES.includes(value)) {
return true;
}
if (helpers_1.BOOLEAN_NEGATIVES.includes(value)) {
return false;
}
throw new utils_1.Exception(message ||
`Value for environment variable "${key}" must be a boolean, instead received "${value}"`, 500, 'E_INVALID_ENV_VALUE');
}
/**
* Enforces the value to be of type boolean. Also casts
* string representation of a boolean to a boolean
* type
*/
function boolean(options) {
return function validate(key, value) {
(0, helpers_1.ensureValue)(key, value, options?.message);
return castToBoolean(key, value, options?.message);
};
}
exports.boolean = boolean;
/**
* Same as boolean, but allows undefined values as well.
*/
boolean.optional = function optionalBoolean(options) {
return function validate(key, value) {
if (!value) {
return undefined;
}
return castToBoolean(key, value, options?.message);
};
};
+12
View File
@@ -0,0 +1,12 @@
/**
* Following values are considered as "true"
*/
export declare const BOOLEAN_POSITIVES: (string | number | boolean)[];
/**
* Following values are considered as "false"
*/
export declare const BOOLEAN_NEGATIVES: (string | number | boolean)[];
/**
* Ensures the value to exist
*/
export declare function ensureValue(key: string, value?: string, message?: string): asserts value is string;
+29
View File
@@ -0,0 +1,29 @@
"use strict";
/*
* @adonisjs/env
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ensureValue = exports.BOOLEAN_NEGATIVES = exports.BOOLEAN_POSITIVES = void 0;
const utils_1 = require("@poppinss/utils");
/**
* Following values are considered as "true"
*/
exports.BOOLEAN_POSITIVES = ['1', 1, 'true', true];
/**
* Following values are considered as "false"
*/
exports.BOOLEAN_NEGATIVES = ['0', 0, 'false', false];
/**
* Ensures the value to exist
*/
function ensureValue(key, value, message) {
if (!value) {
throw new utils_1.Exception(message || `Missing environment variable "${key}"`, 500, 'E_MISSING_ENV_VALUE');
}
}
exports.ensureValue = ensureValue;
+2
View File
@@ -0,0 +1,2 @@
import { EnvSchema } from '@ioc:Adonis/Core/Env';
export declare const schema: EnvSchema;
+21
View File
@@ -0,0 +1,21 @@
"use strict";
/*
* @adonisjs/env
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.schema = void 0;
const number_1 = require("./number");
const string_1 = require("./string");
const boolean_1 = require("./boolean");
const oneOf_1 = require("./oneOf");
exports.schema = {
number: number_1.number,
string: string_1.string,
boolean: boolean_1.boolean,
enum: oneOf_1.oneOf,
};
+13
View File
@@ -0,0 +1,13 @@
import { SchemaFnOptions } from '@ioc:Adonis/Core/Env';
/**
* Casts the string to a number and ensures it is no NaN
*/
export declare function castToNumber(key: string, value: string, message?: string): number;
/**
* Enforces the value to be of valid number type and the
* value will also be casted to a number
*/
export declare function number(options?: SchemaFnOptions): (key: string, value?: string | undefined) => number;
export declare namespace number {
var optional: (options?: SchemaFnOptions | undefined) => (key: string, value?: string | undefined) => number | undefined;
}
+48
View File
@@ -0,0 +1,48 @@
"use strict";
/*
* @adonisjs/env
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.number = exports.castToNumber = void 0;
const utils_1 = require("@poppinss/utils");
const helpers_1 = require("./helpers");
/**
* Casts the string to a number and ensures it is no NaN
*/
function castToNumber(key, value, message) {
const castedValue = Number(value);
if (isNaN(castedValue)) {
throw new utils_1.Exception(message ||
`Value for environment variable "${key}" must be numeric, instead received "${value}"`, 500, 'E_INVALID_ENV_VALUE');
}
return castedValue;
}
exports.castToNumber = castToNumber;
/**
* Enforces the value to be of valid number type and the
* value will also be casted to a number
*/
function number(options) {
return function validate(key, value) {
(0, helpers_1.ensureValue)(key, value, options?.message);
return castToNumber(key, value, options?.message);
};
}
exports.number = number;
/**
* Similar to the number rule, but also allows optional
* values
*/
number.optional = function optionalNumber(options) {
return function validate(key, value) {
if (!value) {
return undefined;
}
return castToNumber(key, value, options?.message);
};
};
+8
View File
@@ -0,0 +1,8 @@
import { SchemaFnOptions } from '@ioc:Adonis/Core/Env';
/**
* Enforces value to be one of the defined choices
*/
export declare function oneOf(choices: any[], options?: SchemaFnOptions): (key: string, value?: string | undefined) => any;
export declare namespace oneOf {
var optional: (choices: any[], options?: SchemaFnOptions | undefined) => (key: string, value?: string | undefined) => any;
}
+69
View File
@@ -0,0 +1,69 @@
"use strict";
/*
* @adonisjs/env
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.oneOf = void 0;
const utils_1 = require("@poppinss/utils");
const helpers_1 = require("./helpers");
/**
* Validates the number to be present in the user defined choices.
*
* The incoming value will be casted as follows:
*
* - "0", 0, "false", false will be casted to false
* - "1", 1, "true", true will be casted to true
* - string representation of a number will be casted to a number
*/
function ensureOneOf(choices, key, value, message) {
if (helpers_1.BOOLEAN_NEGATIVES.includes(value)) {
value = false;
}
else if (helpers_1.BOOLEAN_POSITIVES.includes(value)) {
value = true;
}
else {
const toNumber = Number(value);
if (!isNaN(toNumber)) {
value = toNumber;
}
}
/**
* If choices includes the value, then return the casted
* value
*/
if (choices.includes(value)) {
return value;
}
/**
* Otherwise raise exception
*/
throw new utils_1.Exception(message ||
`Value for environment variable "${key}" must be one of "${choices.join(',')}", instead received "${value}"`, 500, 'E_INVALID_ENV_VALUE');
}
/**
* Enforces value to be one of the defined choices
*/
function oneOf(choices, options) {
return function validate(key, value) {
(0, helpers_1.ensureValue)(key, value, options?.message);
return ensureOneOf(choices, key, value, options?.message);
};
}
exports.oneOf = oneOf;
/**
* Similar to oneOf, but also allows optional properties
*/
oneOf.optional = function optionalBoolean(choices, options) {
return function validate(key, value) {
if (!value) {
return undefined;
}
return ensureOneOf(choices, key, value, options?.message);
};
};
+8
View File
@@ -0,0 +1,8 @@
import { StringFnOptions } from '@ioc:Adonis/Core/Env';
/**
* Enforces the value to exist and be of type string
*/
export declare function string(options?: StringFnOptions): (key: string, value?: string | undefined) => string;
export declare namespace string {
var optional: (options?: StringFnOptions | undefined) => (key: string, value?: string | undefined) => string | undefined;
}
+66
View File
@@ -0,0 +1,66 @@
"use strict";
/*
* @adonisjs/env
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.string = void 0;
const utils_1 = require("@poppinss/utils");
const helpers_1 = require("./helpers");
/**
* Formats against which a string can be optionally validated. We
* lazy load the dependencies required for validating formats
*/
const formats = {
email: (key, value, options) => {
if (!require('validator/lib/isEmail')(value)) {
throw new utils_1.Exception(options.message ||
`Value for environment variable "${key}" must be a valid email, instead received "${value}"`, 500, 'E_INVALID_ENV_VALUE');
}
},
host: (key, value, options) => {
if (!require('validator/lib/isFQDN')(value, { require_tld: false }) &&
!require('validator/lib/isIP')(value)) {
throw new utils_1.Exception(options.message ||
`Value for environment variable "${key}" must be a valid (domain or ip), instead received "${value}"`, 500, 'E_INVALID_ENV_VALUE');
}
},
url: (key, value, options) => {
const { tld = true, protocol = true } = options;
if (!require('validator/lib/isURL')(value, { require_tld: tld, require_protocol: protocol })) {
throw new utils_1.Exception(options.message ||
`Value for environment variable "${key}" must be a valid URL, instead received "${value}"`, 500, 'E_INVALID_ENV_VALUE');
}
},
};
/**
* Enforces the value to exist and be of type string
*/
function string(options) {
return function validate(key, value) {
(0, helpers_1.ensureValue)(key, value, options?.message);
if (options?.format) {
formats[options.format](key, value, options);
}
return value;
};
}
exports.string = string;
/**
* Same as the string rule, but allows non-existing values too
*/
string.optional = function optionalString(options) {
return function validate(key, value) {
if (!value) {
return undefined;
}
if (options?.format) {
formats[options.format](key, value, options);
}
return value;
};
};
+7
View File
@@ -0,0 +1,7 @@
/**
* Reads `.env` file contents
*/
export declare function envLoader(appRoot: string): {
envContents: string;
testEnvContent: string;
};
+53
View File
@@ -0,0 +1,53 @@
"use strict";
/*
* @adonisjs/env
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.envLoader = void 0;
const fs_1 = require("fs");
const path_1 = require("path");
const utils_1 = require("@poppinss/utils");
/**
* Loads file from the disk and optionally ignores the missing
* file errors
*/
function loadFile(filePath, optional = false) {
try {
return (0, fs_1.readFileSync)(filePath, 'utf-8');
}
catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
if (!optional) {
throw new utils_1.Exception(`The "${filePath}" file is missing`, 500, 'E_MISSING_ENV_FILE');
}
}
return '';
}
/**
* Reads `.env` file contents
*/
function envLoader(appRoot) {
const envPath = process.env.ENV_PATH || '.env';
const absPath = (0, path_1.isAbsolute)(envPath) ? envPath : (0, path_1.join)(appRoot, envPath);
const envContents = loadFile(absPath, true);
/**
* Optionally load the `.env.test` and `.env.testing` files
* in test environment
*/
let testEnvContent = '';
if (process.env.NODE_ENV === 'testing') {
testEnvContent = loadFile((0, path_1.join)(appRoot, '.env.testing'), true);
}
else if (process.env.NODE_ENV === 'test') {
testEnvContent = loadFile((0, path_1.join)(appRoot, '.env.test'), true);
}
return { testEnvContent, envContents };
}
exports.envLoader = envLoader;