UNPKG

13.5 kBJavaScriptView Raw
1"use strict";
2var __assign = (this && this.__assign) || function () {
3 __assign = Object.assign || function(t) {
4 for (var s, i = 1, n = arguments.length; i < n; i++) {
5 s = arguments[i];
6 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7 t[p] = s[p];
8 }
9 return t;
10 };
11 return __assign.apply(this, arguments);
12};
13var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
14 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
15 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
16 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
17 return c > 3 && r && Object.defineProperty(target, key, r), r;
18};
19var __metadata = (this && this.__metadata) || function (k, v) {
20 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
21};
22Object.defineProperty(exports, "__esModule", { value: true });
23exports.Config = void 0;
24var cosmiconfig_1 = require("cosmiconfig");
25var Debug = require("debug");
26var dotenv = require("dotenv");
27var fs = require("fs");
28var path = require("path");
29var typedi_1 = require("typedi");
30var utils_1 = require("../utils");
31var debug = Debug('warthog:config');
32var CONFIG_VALUE_VALID_KEYS = [
33 'allowOptionalIdOnCreate',
34 'generatedFolder',
35 'cliGeneratePath',
36 'moduleImportPath',
37 'resolversPath',
38 'validateResolvers'
39];
40var Config = /** @class */ (function () {
41 function Config(options) {
42 if (options === void 0) { options = {}; }
43 this.options = options;
44 this.WARTHOG_ENV_PREFIX = 'WARTHOG_';
45 this.TYPEORM_ENV_PREFIX = 'TYPEORM_';
46 this.WARTHOG_DB_ENV_PREFIX = 'WARTHOG_DB_';
47 this.PROJECT_ROOT = process.cwd();
48 this.container = options.container || typedi_1.Container;
49 this.logger = options.logger;
50 this.defaults = {
51 WARTHOG_DB_CONNECTION: 'postgres',
52 WARTHOG_ROOT_FOLDER: this.PROJECT_ROOT,
53 WARTHOG_ALLOW_OPTIONAL_ID_ON_CREATE: 'false',
54 WARTHOG_APP_PROTOCOL: 'https',
55 WARTHOG_AUTO_GENERATE_FILES: 'false',
56 WARTHOG_AUTO_OPEN_PLAYGROUND: 'false',
57 WARTHOG_INTROSPECTION: 'true',
58 WARTHOG_CLI_GENERATE_PATH: './src',
59 WARTHOG_DB_ENTITIES: [path.join(this.PROJECT_ROOT, 'src/**/*.model.ts')],
60 WARTHOG_DB_ENTITIES_DIR: 'src/models',
61 WARTHOG_DB_LOGGER: 'advanced-console',
62 WARTHOG_DB_MIGRATIONS: ['db/migrations/**/*.ts'],
63 WARTHOG_DB_MIGRATIONS_DIR: 'db/migrations',
64 WARTHOG_DB_PORT: 5432,
65 WARTHOG_DB_SUBSCRIBERS: ['src/subscribers/**/*.ts'],
66 WARTHOG_DB_SUBSCRIBERS_DIR: 'src/subscribers',
67 WARTHOG_DB_SYNCHRONIZE: 'false',
68 WARTHOG_FILTER_BY_DEFAULT: 'true',
69 WARTHOG_MODULE_IMPORT_PATH: 'warthog',
70 // TODO: eventually we should do this path resolution when we ask for the variable with `get`
71 WARTHOG_GENERATED_FOLDER: path.join(this.PROJECT_ROOT, 'generated'),
72 WARTHOG_RESOLVERS_PATH: [path.join(this.PROJECT_ROOT, 'src/**/*.resolver.ts')],
73 WARTHOG_SUBSCRIPTIONS: 'false',
74 WARTHOG_VALIDATE_RESOLVERS: 'false',
75 // Prevent 502s from happening in AWS and GCP (and probably other Production ENVs)
76 // See https://shuheikagawa.com/blog/2019/04/25/keep-alive-timeout/
77 WARTHOG_KEEP_ALIVE_TIMEOUT_MS: 30000,
78 WARTHOG_HEADERS_TIMEOUT_MS: 60000
79 };
80 this.devDefaults = {
81 WARTHOG_APP_HOST: 'localhost',
82 WARTHOG_APP_PORT: '4000',
83 WARTHOG_APP_PROTOCOL: 'http',
84 WARTHOG_AUTO_GENERATE_FILES: 'true',
85 WARTHOG_AUTO_OPEN_PLAYGROUND: 'true',
86 WARTHOG_DB_HOST: 'localhost',
87 WARTHOG_DB_LOGGING: 'all'
88 };
89 this.testDefaults = {
90 WARTHOG_APP_HOST: 'localhost',
91 WARTHOG_APP_PORT: '4000',
92 WARTHOG_APP_PROTOCOL: 'http',
93 WARTHOG_AUTO_GENERATE_FILES: 'false',
94 WARTHOG_AUTO_OPEN_PLAYGROUND: 'false',
95 WARTHOG_DB_DATABASE: 'warthog-test',
96 WARTHOG_DB_HOST: 'localhost',
97 WARTHOG_DB_USERNAME: 'postgres'
98 };
99 var dotenvPath = options.dotenvPath || this.PROJECT_ROOT;
100 this.NODE_ENV = this.determineNodeEnv(dotenvPath);
101 this.loadDotenvFiles(dotenvPath);
102 return this.loadSync();
103 }
104 // Allow NODE_ENV to be set in the .env file. Check for this first here and then fall back on
105 // the environment variable. The reason we do this is because using dotenvi will allow us to switch
106 // between environments. If we require an actual environment variable to be set then we'll have to set
107 // and unset the value in the current terminal buffer.
108 Config.prototype.determineNodeEnv = function (dotenvPath) {
109 var nodeEnv = process.env.NODE_ENV;
110 var filepath = path.join(dotenvPath, '.env');
111 if (fs.existsSync(filepath)) {
112 var config = dotenv.parse(fs.readFileSync(filepath));
113 if (config.NODE_ENV) {
114 nodeEnv = config.NODE_ENV;
115 }
116 }
117 return (this.NODE_ENV = process.env.NODE_ENV = nodeEnv);
118 };
119 Config.prototype.loadDotenvFiles = function (dotenvPath) {
120 // .local files are for secrets, load those first
121 var files = [".env.local." + this.NODE_ENV, '.env.local', '.env'];
122 files.forEach(function (filename) {
123 var filepath = path.join(dotenvPath, filename);
124 if (fs.existsSync(filepath)) {
125 dotenv.config({
126 path: filepath
127 });
128 }
129 });
130 };
131 Config.prototype.loadSync = function () {
132 var devOptions = this.NODE_ENV === 'development' ? this.devDefaults : {};
133 var testOptions = this.NODE_ENV === 'test' ? this.testDefaults : {};
134 var configFile = this.loadStaticConfigSync();
135 // Config is loaded as a waterfall. Items at the top of the object are overwritten by those below, so the order is:
136 // - Add application-wide defaults
137 // - Add development defaults (if we're runnign in DEV mode)
138 // - Load config from config file
139 // - Load environment variables
140 // - Override with locked options
141 var combined = __assign(__assign(__assign(__assign(__assign(__assign({}, this.defaults), devOptions), testOptions), configFile), this.typeORMToWarthogEnvVariables()), this.warthogEnvVariables());
142 // If Jest is running, be smart and don't open playground
143 if (typeof process.env.JEST_WORKER_ID !== 'undefined') {
144 combined.WARTHOG_AUTO_OPEN_PLAYGROUND = 'false';
145 }
146 this.config = combined;
147 debug('Config', this.config);
148 // Must be after config is set above
149 this.validateEntryExists('WARTHOG_APP_HOST');
150 this.validateEntryExists('WARTHOG_APP_PORT');
151 this.validateEntryExists('WARTHOG_GENERATED_FOLDER');
152 this.validateEntryExists('WARTHOG_DB_CONNECTION');
153 this.validateEntryExists('WARTHOG_DB_HOST');
154 // Now that we've pulled all config in from the waterfall, write `WARTHOG_DB_` keys to `TYPEORM_`
155 // So that TypeORM will pick them up
156 // this.writeWarthogConfigToTypeORMEnvVars();
157 // Once we've combined all of the Warthog ENV vars, write them to process.env so that they can be used elsewhere
158 // NOTE: this is likely a bad idea and we should use Containers
159 this.writeWarthogEnvVars();
160 this.container.set('warthog.logger', this.logger); // Save for later so we can pull globally
161 if (this.logger && this.logger.debug) {
162 this.logger.debug('loadSync complete', this.get());
163 }
164 return this;
165 };
166 Config.prototype.get = function (key) {
167 if (typeof key === 'undefined') {
168 return this.config;
169 }
170 else if (!key) {
171 console.error('Config.get: key cannot be blank');
172 }
173 var lookup = key.startsWith(this.WARTHOG_ENV_PREFIX)
174 ? key
175 : "" + this.WARTHOG_ENV_PREFIX + key;
176 return this.config[lookup];
177 };
178 Config.prototype.warthogEnvVariables = function () {
179 return this.envVarsByPrefix(this.WARTHOG_ENV_PREFIX);
180 };
181 Config.prototype.warthogDBEnvVariables = function () {
182 return this.envVarsByPrefix(this.WARTHOG_DB_ENV_PREFIX);
183 };
184 Config.prototype.typeORMEnvVariables = function () {
185 return this.envVarsByPrefix(this.TYPEORM_ENV_PREFIX);
186 };
187 Config.prototype.translateEnvVar = function (key, value) {
188 var _this = this;
189 var arrayTypes = [
190 'WARTHOG_DB_ENTITIES',
191 'WARTHOG_DB_MIGRATIONS',
192 'WARTHOG_DB_SUBSCRIBERS',
193 'WARTHOG_RESOLVERS_PATH'
194 ];
195 var pathTypes = ['WARTHOG_GENERATED_FOLDER'];
196 // Should be able to do this, but TypeGraphQL has an issue with relative requires
197 // https://github.com/19majkel94/type-graphql/blob/a212fd19f28d3095244c44381617f03e97ec4db3/src/helpers/loadResolversFromGlob.ts#L4
198 // const paths = value.split(',');
199 if (arrayTypes.indexOf(key) > -1) {
200 return value.split(',').map(function (item) {
201 if (path.isAbsolute(item)) {
202 return item;
203 }
204 return path.join(_this.PROJECT_ROOT, item);
205 });
206 }
207 if (pathTypes.indexOf(key) > -1) {
208 if (path.isAbsolute(value)) {
209 return value;
210 }
211 return path.join(this.PROJECT_ROOT, value);
212 }
213 return value;
214 };
215 Config.prototype.envVarsByPrefix = function (prefix) {
216 var _this = this;
217 var config = {};
218 Object.keys(process.env).forEach(function (key) {
219 if (key.startsWith(prefix)) {
220 config[key] = _this.translateEnvVar(key, process.env[key] || '');
221 }
222 });
223 return config;
224 };
225 Config.prototype.typeORMToWarthogEnvVariables = function () {
226 var _this = this;
227 var typeORMvars = this.typeORMEnvVariables();
228 var config = {};
229 Object.keys(typeORMvars).forEach(function (key) {
230 var keySuffix = key.substring(_this.TYPEORM_ENV_PREFIX.length);
231 config["" + _this.WARTHOG_DB_ENV_PREFIX + keySuffix] = typeORMvars[key];
232 });
233 return config;
234 };
235 // public writeWarthogConfigToTypeORMEnvVars() {
236 // Object.keys(this.config).forEach((key: string) => {
237 // if (key.startsWith(this.WARTHOG_DB_ENV_PREFIX)) {
238 // const keySuffix = key.substring(this.WARTHOG_DB_ENV_PREFIX.length);
239 // process.env[`TYPEORM_${keySuffix}`] = this.get(key);
240 // }
241 // });
242 // }
243 Config.prototype.writeWarthogEnvVars = function () {
244 var _this = this;
245 Object.keys(this.config).forEach(function (key) {
246 if (key.startsWith(_this.WARTHOG_ENV_PREFIX)) {
247 process.env[key] = _this.get(key);
248 }
249 });
250 };
251 Config.prototype.validateEntryExists = function (key) {
252 if (!this.config) {
253 throw new Error("Can't validate the base config until after it is generated");
254 }
255 var value = this.get(key);
256 if (!value) {
257 throw new Error("Config: " + key + " is required: " + value + "\n\n" + JSON.stringify(this.config) + "\n\n" + JSON.stringify(process.env));
258 }
259 };
260 Config.prototype.loadStaticConfigSync = function () {
261 var response = this.loadStaticConfigFileSync();
262 if (typeof response === 'undefined') {
263 return {};
264 }
265 var constantized = utils_1.ObjectUtil.constantizeKeys(response.config);
266 return utils_1.ObjectUtil.prefixKeys(constantized, this.WARTHOG_ENV_PREFIX);
267 };
268 // Use cosmiconfig to load static config that has to be the same for all environments
269 // paths to folders for the most part
270 Config.prototype.loadStaticConfigFileSync = function () {
271 var explorer = cosmiconfig_1.cosmiconfigSync('warthog');
272 // Pull config values from cosmiconfig
273 var results = explorer.search(this.options.configSearchPath);
274 if (!results || results.isEmpty) {
275 return;
276 }
277 var userConfigKeys = Object.keys(results.config);
278 var badKeys = userConfigKeys.filter(function (x) { return !CONFIG_VALUE_VALID_KEYS.includes(x); });
279 if (badKeys.length) {
280 throw new Error("Config: invalid keys specified in " + results.filepath + ": [" + badKeys.join(', ') + "]");
281 }
282 // Make sure the generated folder is an absolute path
283 if (results.config.generatedFolder && !path.isAbsolute(results.config.generatedFolder)) {
284 results.config.generatedFolder = path.join(path.dirname(results.filepath), results.config.generatedFolder);
285 }
286 return results;
287 };
288 Config = __decorate([
289 typedi_1.Service('Config'),
290 __metadata("design:paramtypes", [Object])
291 ], Config);
292 return Config;
293}());
294exports.Config = Config;
295//# sourceMappingURL=config.js.map
\No newline at end of file