@balena/env-parsing 1.0.0-v1-a51169ccd2023cd96cdc4213fb2af46a7ee5bd9b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +16 -0
- package/CHANGELOG.md +10 -0
- package/README.md +3 -0
- package/build/index.d.ts +38 -0
- package/build/index.js +124 -0
- package/build/index.js.map +1 -0
- package/package.json +57 -0
- package/src/index.ts +158 -0
- package/test/index.ts +201 -0
- package/tsconfig.json +16 -0
package/.editorconfig
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# editorconfig.org
|
|
2
|
+
root = true
|
|
3
|
+
|
|
4
|
+
[*]
|
|
5
|
+
indent_style = tab
|
|
6
|
+
end_of_line = lf
|
|
7
|
+
charset = utf-8
|
|
8
|
+
trim_trailing_whitespace = true
|
|
9
|
+
insert_final_newline = true
|
|
10
|
+
|
|
11
|
+
[*.md]
|
|
12
|
+
trim_trailing_whitespace = false
|
|
13
|
+
|
|
14
|
+
[package.json]
|
|
15
|
+
indent_style = space
|
|
16
|
+
indent_size = 2
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file
|
|
4
|
+
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
|
|
5
|
+
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
|
+
|
|
7
|
+
# v1.0.0
|
|
8
|
+
## (2022-08-12)
|
|
9
|
+
|
|
10
|
+
* Initial version [Pagan Gazzard]
|
package/README.md
ADDED
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare const SECONDS = 1000;
|
|
2
|
+
export declare const SECONDS_PER_HOUR: number;
|
|
3
|
+
export declare const MINUTES: number;
|
|
4
|
+
export declare const HOURS: number;
|
|
5
|
+
export declare const DAYS: number;
|
|
6
|
+
/**
|
|
7
|
+
* Ensure an env var exists and return the contents if it does
|
|
8
|
+
*/
|
|
9
|
+
export declare const requiredVar: (varName: string) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Fetches the contents of an env var if it exists and is not empty, otherwise returning the specified default value,
|
|
12
|
+
* this means that if no default is specified then `''` will be normalized to `undefined`
|
|
13
|
+
*/
|
|
14
|
+
export declare function optionalVar<R>(varName: string, defaultValue: R): string | R;
|
|
15
|
+
export declare function optionalVar<R>(varName: string, defaultValue?: undefined): string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Checks that a string is a valid int and returns the number if so
|
|
18
|
+
*/
|
|
19
|
+
export declare const checkInt: (s: string) => number | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Fetches the contents of an env var, ensuring it is a valid integer if set, if it is not set then instead it returns the specified default value
|
|
22
|
+
*/
|
|
23
|
+
export declare function intVar(varName: string): number;
|
|
24
|
+
export declare function intVar<R>(varName: string, defaultValue: R): number | R;
|
|
25
|
+
/**
|
|
26
|
+
* Fetches the contents of an env var, ensuring it is a valid boolean (`'true'`/`'false'`) if set, if it is not set then instead it returns the specified default value
|
|
27
|
+
*/
|
|
28
|
+
export declare function boolVar(varName: string): boolean;
|
|
29
|
+
export declare function boolVar<R>(varName: string, defaultValue: R): boolean | R;
|
|
30
|
+
export declare type HostPort = {
|
|
31
|
+
host: string;
|
|
32
|
+
port: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Splits an env var in the format of `${host1}:${port1}, ${host2}:${port2}, ...` into an array of individual host/port pairings
|
|
36
|
+
*/
|
|
37
|
+
export declare const splitHostPort: (varName: string, defaultHosts?: HostPort[]) => HostPort[];
|
|
38
|
+
export declare const trustProxyVar: (varName: string, defaultValue?: string) => boolean | string | number;
|
package/build/index.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trustProxyVar = exports.splitHostPort = exports.boolVar = exports.intVar = exports.checkInt = exports.optionalVar = exports.requiredVar = exports.DAYS = exports.HOURS = exports.MINUTES = exports.SECONDS_PER_HOUR = exports.SECONDS = void 0;
|
|
4
|
+
exports.SECONDS = 1000;
|
|
5
|
+
exports.SECONDS_PER_HOUR = 60 * 60;
|
|
6
|
+
exports.MINUTES = 60 * exports.SECONDS;
|
|
7
|
+
exports.HOURS = 60 * exports.MINUTES;
|
|
8
|
+
exports.DAYS = 24 * exports.HOURS;
|
|
9
|
+
/**
|
|
10
|
+
* Ensure an env var exists and return the contents if it does
|
|
11
|
+
*/
|
|
12
|
+
const requiredVar = (varName) => {
|
|
13
|
+
const s = optionalVar(varName);
|
|
14
|
+
if (s == null) {
|
|
15
|
+
throw new Error(`Missing environment variable: ${varName}`);
|
|
16
|
+
}
|
|
17
|
+
return s;
|
|
18
|
+
};
|
|
19
|
+
exports.requiredVar = requiredVar;
|
|
20
|
+
function optionalVar(varName, defaultValue) {
|
|
21
|
+
const s = process.env[varName];
|
|
22
|
+
if (s == null || s === '') {
|
|
23
|
+
return defaultValue;
|
|
24
|
+
}
|
|
25
|
+
return s;
|
|
26
|
+
}
|
|
27
|
+
exports.optionalVar = optionalVar;
|
|
28
|
+
/**
|
|
29
|
+
* Checks that a string is a valid int and returns the number if so
|
|
30
|
+
*/
|
|
31
|
+
const checkInt = (s) => {
|
|
32
|
+
s = s.trim();
|
|
33
|
+
if (/[^0-9]/.test(s)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const i = parseInt(s, 10);
|
|
37
|
+
if (!Number.isFinite(i)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
return i;
|
|
41
|
+
};
|
|
42
|
+
exports.checkInt = checkInt;
|
|
43
|
+
function intVar(varName, defaultValue) {
|
|
44
|
+
if (arguments.length === 1) {
|
|
45
|
+
(0, exports.requiredVar)(varName);
|
|
46
|
+
}
|
|
47
|
+
const s = optionalVar(varName);
|
|
48
|
+
if (s == null) {
|
|
49
|
+
return defaultValue;
|
|
50
|
+
}
|
|
51
|
+
const i = (0, exports.checkInt)(s);
|
|
52
|
+
if (i === undefined) {
|
|
53
|
+
throw new Error(`${varName} must be a valid number if set`);
|
|
54
|
+
}
|
|
55
|
+
return i;
|
|
56
|
+
}
|
|
57
|
+
exports.intVar = intVar;
|
|
58
|
+
function boolVar(varName, defaultValue) {
|
|
59
|
+
if (arguments.length === 1) {
|
|
60
|
+
(0, exports.requiredVar)(varName);
|
|
61
|
+
}
|
|
62
|
+
const s = optionalVar(varName);
|
|
63
|
+
if (s == null) {
|
|
64
|
+
return defaultValue;
|
|
65
|
+
}
|
|
66
|
+
if (s === 'false') {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
if (s === 'true') {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Invalid value for boolean var '${varName}', got '${s}', expected 'true' or 'false'`);
|
|
73
|
+
}
|
|
74
|
+
exports.boolVar = boolVar;
|
|
75
|
+
/**
|
|
76
|
+
* Splits an env var in the format of `${host1}:${port1}, ${host2}:${port2}, ...` into an array of individual host/port pairings
|
|
77
|
+
*/
|
|
78
|
+
const splitHostPort = (varName, defaultHosts) => {
|
|
79
|
+
const hostPairs = optionalVar(varName);
|
|
80
|
+
if (hostPairs == null) {
|
|
81
|
+
if (defaultHosts == null) {
|
|
82
|
+
throw new Error(`Missing environment variable: ${varName}`);
|
|
83
|
+
}
|
|
84
|
+
return defaultHosts;
|
|
85
|
+
}
|
|
86
|
+
return hostPairs.split(',').map((hostPair) => {
|
|
87
|
+
const [host, maybePort] = hostPair.trim().split(':');
|
|
88
|
+
const port = (0, exports.checkInt)(maybePort);
|
|
89
|
+
if (port == null) {
|
|
90
|
+
throw new Error(`Invalid port for '${varName}': ${maybePort}`);
|
|
91
|
+
}
|
|
92
|
+
return { host, port };
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
exports.splitHostPort = splitHostPort;
|
|
96
|
+
const trustProxyVar = (varName, defaultValue) => {
|
|
97
|
+
const trustProxy = optionalVar(varName, defaultValue);
|
|
98
|
+
if (trustProxy == null) {
|
|
99
|
+
throw new Error(`Missing environment variable: ${varName}`);
|
|
100
|
+
}
|
|
101
|
+
if (trustProxy === 'true') {
|
|
102
|
+
// If it's 'true' enable it
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
if (trustProxy === 'false') {
|
|
106
|
+
// If it's 'false' disable it
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if (trustProxy.includes('.') || trustProxy.includes(':')) {
|
|
110
|
+
// If it looks like an ip use as-is
|
|
111
|
+
return trustProxy;
|
|
112
|
+
}
|
|
113
|
+
const trustProxyNum = (0, exports.checkInt)(trustProxy);
|
|
114
|
+
if (trustProxyNum != null) {
|
|
115
|
+
// If it's a number use the number
|
|
116
|
+
return trustProxyNum;
|
|
117
|
+
}
|
|
118
|
+
if (trustProxy === defaultValue) {
|
|
119
|
+
throw new Error(`Invalid default value for '${varName}' of '${trustProxy}'`);
|
|
120
|
+
}
|
|
121
|
+
throw new Error(`Invalid value for '${varName}' of '${trustProxy}'`);
|
|
122
|
+
};
|
|
123
|
+
exports.trustProxyVar = trustProxyVar;
|
|
124
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,IAAI,CAAC;AACf,QAAA,gBAAgB,GAAG,EAAE,GAAG,EAAE,CAAC;AAC3B,QAAA,OAAO,GAAG,EAAE,GAAG,eAAO,CAAC;AACvB,QAAA,KAAK,GAAG,EAAE,GAAG,eAAO,CAAC;AACrB,QAAA,IAAI,GAAG,EAAE,GAAG,aAAK,CAAC;AAE/B;;GAEG;AACI,MAAM,WAAW,GAAG,CAAC,OAAe,EAAU,EAAE;IACtD,MAAM,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI,IAAI,EAAE;QACd,MAAM,IAAI,KAAK,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC;KAC5D;IACD,OAAO,CAAC,CAAC;AACV,CAAC,CAAC;AANW,QAAA,WAAW,eAMtB;AAWF,SAAgB,WAAW,CAC1B,OAAe,EACf,YAAgB;IAEhB,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE;QAC1B,OAAO,YAAY,CAAC;KACpB;IACD,OAAO,CAAC,CAAC;AACV,CAAC;AATD,kCASC;AAED;;GAEG;AACI,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAE,EAAE;IACrC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACb,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;QACrB,OAAO;KACP;IACD,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;QACxB,OAAO;KACP;IACD,OAAO,CAAC,CAAC;AACV,CAAC,CAAC;AAVW,QAAA,QAAQ,YAUnB;AAOF,SAAgB,MAAM,CAAI,OAAe,EAAE,YAAgB;IAC1D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;QAC3B,IAAA,mBAAW,EAAC,OAAO,CAAC,CAAC;KACrB;IAED,MAAM,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI,IAAI,EAAE;QACd,OAAO,YAAa,CAAC;KACrB;IAED,MAAM,CAAC,GAAG,IAAA,gBAAQ,EAAC,CAAC,CAAC,CAAC;IACtB,IAAI,CAAC,KAAK,SAAS,EAAE;QACpB,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,gCAAgC,CAAC,CAAC;KAC5D;IACD,OAAO,CAAC,CAAC;AACV,CAAC;AAfD,wBAeC;AAOD,SAAgB,OAAO,CAAI,OAAe,EAAE,YAAgB;IAC3D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;QAC3B,IAAA,mBAAW,EAAC,OAAO,CAAC,CAAC;KACrB;IAED,MAAM,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI,IAAI,EAAE;QACd,OAAO,YAAa,CAAC;KACrB;IACD,IAAI,CAAC,KAAK,OAAO,EAAE;QAClB,OAAO,KAAK,CAAC;KACb;IACD,IAAI,CAAC,KAAK,MAAM,EAAE;QACjB,OAAO,IAAI,CAAC;KACZ;IACD,MAAM,IAAI,KAAK,CACd,kCAAkC,OAAO,WAAW,CAAC,+BAA+B,CACpF,CAAC;AACH,CAAC;AAlBD,0BAkBC;AAGD;;GAEG;AACI,MAAM,aAAa,GAAG,CAC5B,OAAe,EACf,YAAyB,EACZ,EAAE;IACf,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,SAAS,IAAI,IAAI,EAAE;QACtB,IAAI,YAAY,IAAI,IAAI,EAAE;YACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC;SAC5D;QACD,OAAO,YAAY,CAAC;KACpB;IACD,OAAO,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAY,EAAE;QACtD,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrD,MAAM,IAAI,GAAG,IAAA,gBAAQ,EAAC,SAAS,CAAC,CAAC;QACjC,IAAI,IAAI,IAAI,IAAI,EAAE;YACjB,MAAM,IAAI,KAAK,CAAC,qBAAqB,OAAO,MAAM,SAAS,EAAE,CAAC,CAAC;SAC/D;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC;AAnBW,QAAA,aAAa,iBAmBxB;AAEK,MAAM,aAAa,GAAG,CAC5B,OAAe,EACf,YAAqB,EACO,EAAE;IAC9B,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACtD,IAAI,UAAU,IAAI,IAAI,EAAE;QACvB,MAAM,IAAI,KAAK,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC;KAC5D;IACD,IAAI,UAAU,KAAK,MAAM,EAAE;QAC1B,2BAA2B;QAC3B,OAAO,IAAI,CAAC;KACZ;IACD,IAAI,UAAU,KAAK,OAAO,EAAE;QAC3B,6BAA6B;QAC7B,OAAO,KAAK,CAAC;KACb;IACD,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QACzD,mCAAmC;QACnC,OAAO,UAAU,CAAC;KAClB;IAED,MAAM,aAAa,GAAG,IAAA,gBAAQ,EAAC,UAAU,CAAC,CAAC;IAC3C,IAAI,aAAa,IAAI,IAAI,EAAE;QAC1B,kCAAkC;QAClC,OAAO,aAAa,CAAC;KACrB;IAED,IAAI,UAAU,KAAK,YAAY,EAAE;QAChC,MAAM,IAAI,KAAK,CACd,8BAA8B,OAAO,SAAS,UAAU,GAAG,CAC3D,CAAC;KACF;IACD,MAAM,IAAI,KAAK,CAAC,sBAAsB,OAAO,SAAS,UAAU,GAAG,CAAC,CAAC;AACtE,CAAC,CAAC;AAjCW,QAAA,aAAa,iBAiCxB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@balena/env-parsing",
|
|
3
|
+
"version": "1.0.0-v1-a51169ccd2023cd96cdc4213fb2af46a7ee5bd9b",
|
|
4
|
+
"description": "A collection of utilities to simplify/standardize env var parsing",
|
|
5
|
+
"main": "build/index.js",
|
|
6
|
+
"types": "build/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"clean": "rimraf build",
|
|
9
|
+
"build": "npm run clean && tsc",
|
|
10
|
+
"lint": "balena-lint --typescript src test",
|
|
11
|
+
"lint-fix": "balena-lint --typescript --fix src test",
|
|
12
|
+
"test": "mocha && npm run lint",
|
|
13
|
+
"prepack": "npm run build",
|
|
14
|
+
"prepare": "husky install"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/balena-io-modules/balena-env-parsing.git"
|
|
19
|
+
},
|
|
20
|
+
"author": "Page-",
|
|
21
|
+
"license": "Apache-2.0",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/balena-io-modules/balena-env-parsing/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/balena-io-modules/balena-env-parsing#readme",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@balena/lint": "^6.2.0",
|
|
28
|
+
"@types/chai": "^4.3.3",
|
|
29
|
+
"@types/mocha": "^9.1.1",
|
|
30
|
+
"@types/node": "^16.11.48",
|
|
31
|
+
"chai": "^4.3.6",
|
|
32
|
+
"husky": "^8.0.0",
|
|
33
|
+
"mocha": "^10.0.0",
|
|
34
|
+
"rimraf": "^3.0.2",
|
|
35
|
+
"ts-node": "^10.9.1",
|
|
36
|
+
"typescript": "^4.7.4"
|
|
37
|
+
},
|
|
38
|
+
"mocha": {
|
|
39
|
+
"reporter": "spec",
|
|
40
|
+
"recursive": true,
|
|
41
|
+
"require": "ts-node/register/transpile-only",
|
|
42
|
+
"extension": ".ts"
|
|
43
|
+
},
|
|
44
|
+
"husky": {
|
|
45
|
+
"hooks": {
|
|
46
|
+
"pre-commit": "lint-staged"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"lint-staged": {
|
|
50
|
+
"*.ts": [
|
|
51
|
+
"balena-lint --fix"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"versionist": {
|
|
55
|
+
"publishedAt": "2022-08-12T14:37:20.953Z"
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
export const SECONDS = 1000;
|
|
2
|
+
export const SECONDS_PER_HOUR = 60 * 60;
|
|
3
|
+
export const MINUTES = 60 * SECONDS;
|
|
4
|
+
export const HOURS = 60 * MINUTES;
|
|
5
|
+
export const DAYS = 24 * HOURS;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Ensure an env var exists and return the contents if it does
|
|
9
|
+
*/
|
|
10
|
+
export const requiredVar = (varName: string): string => {
|
|
11
|
+
const s = optionalVar(varName);
|
|
12
|
+
if (s == null) {
|
|
13
|
+
throw new Error(`Missing environment variable: ${varName}`);
|
|
14
|
+
}
|
|
15
|
+
return s;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Fetches the contents of an env var if it exists and is not empty, otherwise returning the specified default value,
|
|
20
|
+
* this means that if no default is specified then `''` will be normalized to `undefined`
|
|
21
|
+
*/
|
|
22
|
+
export function optionalVar<R>(varName: string, defaultValue: R): string | R;
|
|
23
|
+
export function optionalVar<R>(
|
|
24
|
+
varName: string,
|
|
25
|
+
defaultValue?: undefined,
|
|
26
|
+
): string | undefined;
|
|
27
|
+
export function optionalVar<R>(
|
|
28
|
+
varName: string,
|
|
29
|
+
defaultValue?: R,
|
|
30
|
+
): string | R | undefined {
|
|
31
|
+
const s = process.env[varName];
|
|
32
|
+
if (s == null || s === '') {
|
|
33
|
+
return defaultValue;
|
|
34
|
+
}
|
|
35
|
+
return s;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Checks that a string is a valid int and returns the number if so
|
|
40
|
+
*/
|
|
41
|
+
export const checkInt = (s: string) => {
|
|
42
|
+
s = s.trim();
|
|
43
|
+
if (/[^0-9]/.test(s)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const i = parseInt(s, 10);
|
|
47
|
+
if (!Number.isFinite(i)) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
return i;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Fetches the contents of an env var, ensuring it is a valid integer if set, if it is not set then instead it returns the specified default value
|
|
55
|
+
*/
|
|
56
|
+
export function intVar(varName: string): number;
|
|
57
|
+
export function intVar<R>(varName: string, defaultValue: R): number | R;
|
|
58
|
+
export function intVar<R>(varName: string, defaultValue?: R): number | R {
|
|
59
|
+
if (arguments.length === 1) {
|
|
60
|
+
requiredVar(varName);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const s = optionalVar(varName);
|
|
64
|
+
if (s == null) {
|
|
65
|
+
return defaultValue!;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const i = checkInt(s);
|
|
69
|
+
if (i === undefined) {
|
|
70
|
+
throw new Error(`${varName} must be a valid number if set`);
|
|
71
|
+
}
|
|
72
|
+
return i;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Fetches the contents of an env var, ensuring it is a valid boolean (`'true'`/`'false'`) if set, if it is not set then instead it returns the specified default value
|
|
77
|
+
*/
|
|
78
|
+
export function boolVar(varName: string): boolean;
|
|
79
|
+
export function boolVar<R>(varName: string, defaultValue: R): boolean | R;
|
|
80
|
+
export function boolVar<R>(varName: string, defaultValue?: R): boolean | R {
|
|
81
|
+
if (arguments.length === 1) {
|
|
82
|
+
requiredVar(varName);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const s = optionalVar(varName);
|
|
86
|
+
if (s == null) {
|
|
87
|
+
return defaultValue!;
|
|
88
|
+
}
|
|
89
|
+
if (s === 'false') {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
if (s === 'true') {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Invalid value for boolean var '${varName}', got '${s}', expected 'true' or 'false'`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export type HostPort = { host: string; port: number };
|
|
101
|
+
/**
|
|
102
|
+
* Splits an env var in the format of `${host1}:${port1}, ${host2}:${port2}, ...` into an array of individual host/port pairings
|
|
103
|
+
*/
|
|
104
|
+
export const splitHostPort = (
|
|
105
|
+
varName: string,
|
|
106
|
+
defaultHosts?: HostPort[],
|
|
107
|
+
): HostPort[] => {
|
|
108
|
+
const hostPairs = optionalVar(varName);
|
|
109
|
+
if (hostPairs == null) {
|
|
110
|
+
if (defaultHosts == null) {
|
|
111
|
+
throw new Error(`Missing environment variable: ${varName}`);
|
|
112
|
+
}
|
|
113
|
+
return defaultHosts;
|
|
114
|
+
}
|
|
115
|
+
return hostPairs.split(',').map((hostPair): HostPort => {
|
|
116
|
+
const [host, maybePort] = hostPair.trim().split(':');
|
|
117
|
+
const port = checkInt(maybePort);
|
|
118
|
+
if (port == null) {
|
|
119
|
+
throw new Error(`Invalid port for '${varName}': ${maybePort}`);
|
|
120
|
+
}
|
|
121
|
+
return { host, port };
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const trustProxyVar = (
|
|
126
|
+
varName: string,
|
|
127
|
+
defaultValue?: string,
|
|
128
|
+
): boolean | string | number => {
|
|
129
|
+
const trustProxy = optionalVar(varName, defaultValue);
|
|
130
|
+
if (trustProxy == null) {
|
|
131
|
+
throw new Error(`Missing environment variable: ${varName}`);
|
|
132
|
+
}
|
|
133
|
+
if (trustProxy === 'true') {
|
|
134
|
+
// If it's 'true' enable it
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
if (trustProxy === 'false') {
|
|
138
|
+
// If it's 'false' disable it
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
if (trustProxy.includes('.') || trustProxy.includes(':')) {
|
|
142
|
+
// If it looks like an ip use as-is
|
|
143
|
+
return trustProxy;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const trustProxyNum = checkInt(trustProxy);
|
|
147
|
+
if (trustProxyNum != null) {
|
|
148
|
+
// If it's a number use the number
|
|
149
|
+
return trustProxyNum;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (trustProxy === defaultValue) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
`Invalid default value for '${varName}' of '${trustProxy}'`,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
throw new Error(`Invalid value for '${varName}' of '${trustProxy}'`);
|
|
158
|
+
};
|
package/test/index.ts
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import {
|
|
3
|
+
boolVar,
|
|
4
|
+
checkInt,
|
|
5
|
+
intVar,
|
|
6
|
+
optionalVar,
|
|
7
|
+
requiredVar,
|
|
8
|
+
splitHostPort,
|
|
9
|
+
trustProxyVar,
|
|
10
|
+
} from '../src';
|
|
11
|
+
|
|
12
|
+
const varName = 'test';
|
|
13
|
+
const clearVar = () => {
|
|
14
|
+
delete process.env[varName];
|
|
15
|
+
};
|
|
16
|
+
const setVar = (v: string) => {
|
|
17
|
+
process.env[varName] = v;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
clearVar();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('requiredVar', () => {
|
|
25
|
+
it('should throw when the env var is missing', () => {
|
|
26
|
+
expect(() => requiredVar(varName)).to.throw;
|
|
27
|
+
});
|
|
28
|
+
it('should return the value when the env var exists', () => {
|
|
29
|
+
const value = 'apple';
|
|
30
|
+
setVar(value);
|
|
31
|
+
expect(requiredVar(varName)).to.equal(value);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('optionalVar', () => {
|
|
36
|
+
const defaultValue = 'banana';
|
|
37
|
+
it('should return undefined when the env var is missing', () => {
|
|
38
|
+
expect(optionalVar(varName)).to.be.undefined;
|
|
39
|
+
});
|
|
40
|
+
it('should return undefined when the env var is empty', () => {
|
|
41
|
+
expect(optionalVar(varName)).to.be.undefined;
|
|
42
|
+
});
|
|
43
|
+
it('should return the default value when the env var is missing', () => {
|
|
44
|
+
expect(optionalVar(varName, defaultValue)).to.equal(defaultValue);
|
|
45
|
+
});
|
|
46
|
+
it('should return the default value when the env var is empty', () => {
|
|
47
|
+
setVar('');
|
|
48
|
+
expect(optionalVar(varName, defaultValue)).to.equal(defaultValue);
|
|
49
|
+
});
|
|
50
|
+
it('should return the value when the env var exists', () => {
|
|
51
|
+
const value = 'coconut';
|
|
52
|
+
setVar(value);
|
|
53
|
+
expect(optionalVar(varName)).to.equal(value);
|
|
54
|
+
expect(optionalVar(varName, defaultValue)).to.equal(value);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('intVar', () => {
|
|
59
|
+
const defaultValue = 'banana';
|
|
60
|
+
it('should throw when the env var is missing', () => {
|
|
61
|
+
expect(() => intVar(varName)).to.throw;
|
|
62
|
+
});
|
|
63
|
+
it('should throw when the env var is invalid', () => {
|
|
64
|
+
setVar('date');
|
|
65
|
+
expect(() => intVar(varName)).to.throw;
|
|
66
|
+
});
|
|
67
|
+
it('should return the default value when the env var is missing', () => {
|
|
68
|
+
expect(intVar(varName, defaultValue)).to.equal(defaultValue);
|
|
69
|
+
});
|
|
70
|
+
it('should return the default value when the env var is empty', () => {
|
|
71
|
+
setVar('');
|
|
72
|
+
expect(intVar(varName, defaultValue)).to.equal(defaultValue);
|
|
73
|
+
});
|
|
74
|
+
it('should return the value when the env var is a valid number', () => {
|
|
75
|
+
const value = 123;
|
|
76
|
+
setVar(`${value}`);
|
|
77
|
+
expect(intVar(varName)).to.equal(value);
|
|
78
|
+
expect(intVar(varName, defaultValue)).to.equal(value);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('boolVar', () => {
|
|
83
|
+
const defaultValue = 'banana';
|
|
84
|
+
it('should throw when the env var is missing', () => {
|
|
85
|
+
expect(() => boolVar(varName)).to.throw;
|
|
86
|
+
});
|
|
87
|
+
it('should throw when the env var is invalid', () => {
|
|
88
|
+
setVar('date');
|
|
89
|
+
expect(() => boolVar(varName)).to.throw;
|
|
90
|
+
});
|
|
91
|
+
it('should return the default value when the env var is missing', () => {
|
|
92
|
+
expect(boolVar(varName, defaultValue)).to.equal(defaultValue);
|
|
93
|
+
});
|
|
94
|
+
it('should return the default value when the env var is empty', () => {
|
|
95
|
+
setVar('');
|
|
96
|
+
expect(boolVar(varName, defaultValue)).to.equal(defaultValue);
|
|
97
|
+
});
|
|
98
|
+
it('should return the value when the env var is true', () => {
|
|
99
|
+
const value = true;
|
|
100
|
+
setVar(`${value}`);
|
|
101
|
+
expect(boolVar(varName)).to.equal(value);
|
|
102
|
+
expect(boolVar(varName, defaultValue)).to.equal(value);
|
|
103
|
+
});
|
|
104
|
+
it('should return the value when the env var is false', () => {
|
|
105
|
+
const value = false;
|
|
106
|
+
setVar(`${value}`);
|
|
107
|
+
expect(boolVar(varName)).to.equal(value);
|
|
108
|
+
expect(boolVar(varName, defaultValue)).to.equal(value);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('splitHostPort', () => {
|
|
113
|
+
const defaultValue = [];
|
|
114
|
+
it('should throw when the env var is missing', () => {
|
|
115
|
+
expect(() => splitHostPort(varName)).to.throw;
|
|
116
|
+
});
|
|
117
|
+
it('should throw when the env var is invalid', () => {
|
|
118
|
+
setVar('date');
|
|
119
|
+
expect(() => splitHostPort(varName)).to.throw;
|
|
120
|
+
});
|
|
121
|
+
it('should return the default value when the env var is missing', () => {
|
|
122
|
+
expect(splitHostPort(varName, defaultValue)).to.equal(defaultValue);
|
|
123
|
+
});
|
|
124
|
+
it('should return the default value when the env var is empty', () => {
|
|
125
|
+
setVar('');
|
|
126
|
+
expect(splitHostPort(varName, defaultValue)).to.equal(defaultValue);
|
|
127
|
+
});
|
|
128
|
+
it('should return the value when the env var is valid', () => {
|
|
129
|
+
const value = [
|
|
130
|
+
{ host: '127.0.0.1', port: 8080 },
|
|
131
|
+
{ host: '10.0.0.1', port: 80 },
|
|
132
|
+
];
|
|
133
|
+
setVar('127.0.0.1:8080, 10.0.0.1:80');
|
|
134
|
+
expect(splitHostPort(varName)).to.deep.equal(value);
|
|
135
|
+
expect(splitHostPort(varName, defaultValue)).to.deep.equal(value);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('trustProxyVar', () => {
|
|
140
|
+
const defaultValue = '127.0.0.1';
|
|
141
|
+
it('should throw when the env var is missing', () => {
|
|
142
|
+
expect(() => trustProxyVar(varName)).to.throw;
|
|
143
|
+
});
|
|
144
|
+
it('should throw when the env var is invalid', () => {
|
|
145
|
+
setVar('date');
|
|
146
|
+
expect(() => trustProxyVar(varName)).to.throw;
|
|
147
|
+
});
|
|
148
|
+
it('should return the default value when the env var is missing', () => {
|
|
149
|
+
expect(trustProxyVar(varName, defaultValue)).to.equal(defaultValue);
|
|
150
|
+
});
|
|
151
|
+
it('should throw when the default var is invalid', () => {
|
|
152
|
+
setVar('date');
|
|
153
|
+
expect(() => trustProxyVar(varName, '')).to.throw;
|
|
154
|
+
});
|
|
155
|
+
it('should return the default value when the env var is empty', () => {
|
|
156
|
+
setVar('');
|
|
157
|
+
expect(trustProxyVar(varName, defaultValue)).to.equal(defaultValue);
|
|
158
|
+
});
|
|
159
|
+
it('should return the value when the env var is a valid number', () => {
|
|
160
|
+
const value = 123;
|
|
161
|
+
setVar(`${value}`);
|
|
162
|
+
expect(trustProxyVar(varName)).to.equal(value);
|
|
163
|
+
expect(trustProxyVar(varName, defaultValue)).to.equal(value);
|
|
164
|
+
});
|
|
165
|
+
it('should return the value when the env var is true', () => {
|
|
166
|
+
const value = true;
|
|
167
|
+
setVar(`${value}`);
|
|
168
|
+
expect(trustProxyVar(varName)).to.equal(value);
|
|
169
|
+
expect(trustProxyVar(varName, defaultValue)).to.equal(value);
|
|
170
|
+
});
|
|
171
|
+
it('should return the value when the env var is false', () => {
|
|
172
|
+
const value = false;
|
|
173
|
+
setVar(`${value}`);
|
|
174
|
+
expect(trustProxyVar(varName)).to.equal(value);
|
|
175
|
+
expect(trustProxyVar(varName, defaultValue)).to.equal(value);
|
|
176
|
+
});
|
|
177
|
+
it('should return the value when the env var is valid', () => {
|
|
178
|
+
const value = '127.0.0.1, 10.0.0.1';
|
|
179
|
+
setVar(value);
|
|
180
|
+
expect(trustProxyVar(varName)).to.deep.equal(value);
|
|
181
|
+
expect(trustProxyVar(varName, defaultValue)).to.deep.equal(value);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe('checkInt', () => {
|
|
186
|
+
it('should fail on an empty value', () => {
|
|
187
|
+
expect(checkInt('')).to.be.undefined;
|
|
188
|
+
});
|
|
189
|
+
it('should fail on a float', () => {
|
|
190
|
+
expect(checkInt('123.456')).to.be.undefined;
|
|
191
|
+
});
|
|
192
|
+
it('should fail on an exponent', () => {
|
|
193
|
+
expect(checkInt('1e3')).to.be.undefined;
|
|
194
|
+
});
|
|
195
|
+
it('should return the value on a valid integer', () => {
|
|
196
|
+
expect(checkInt('1000')).to.equal(1000);
|
|
197
|
+
});
|
|
198
|
+
it('should return the value on a valid integer with leading/trailing spaces', () => {
|
|
199
|
+
expect(checkInt(' 1000 ')).to.equal(1000);
|
|
200
|
+
});
|
|
201
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"outDir": "build",
|
|
5
|
+
"noUnusedParameters": true,
|
|
6
|
+
"noUnusedLocals": true,
|
|
7
|
+
"sourceMap": true,
|
|
8
|
+
"strict": true,
|
|
9
|
+
"target": "es2019",
|
|
10
|
+
"declaration": true,
|
|
11
|
+
"skipLibCheck": true
|
|
12
|
+
},
|
|
13
|
+
"include": [
|
|
14
|
+
"src/**/*.ts"
|
|
15
|
+
]
|
|
16
|
+
}
|