binhend 2.3.7 → 2.3.9

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/index.js CHANGED
@@ -11,7 +11,7 @@ const path = require('path');
11
11
 
12
12
  //___ Run scripts ___//
13
13
  const moduleAlias = require('./packages/module-alias'); // path alias '@' for requiring modules: require('@/any/path') - use jsconfig.json
14
- moduleAlias.path('@binhend/*', [ path.join(__dirname, './packages') ]); // set path alias '@binhend' for all packages to call each others when 'npm install' in another project
14
+ moduleAlias.path('@binhend/*', [path.join(__dirname, './packages')]); // set path alias '@binhend' for all packages to call each others when 'npm install' in another project
15
15
 
16
16
 
17
17
  //___ Load packages ___//
@@ -30,7 +30,7 @@ const csrf = require('./packages/middlewares/src/csrf');
30
30
  const trycatch = require('./packages/middlewares/src/trycatch');
31
31
  const { Auth } = require('./packages/middlewares/src/authorize');
32
32
 
33
- const { config, ConfigLoader } = require('./packages/config/src/configuration');
33
+ const { config, ConfigLoader, env } = require('./packages/config');
34
34
 
35
35
  const CSD = require('./packages/csd/src/csd');
36
36
  const CinCSD = require('./packages/csd/src/controller');
@@ -53,7 +53,7 @@ module.exports = {
53
53
 
54
54
  cors, csrf, trycatch, Auth,
55
55
 
56
- config, ConfigLoader,
56
+ env, config, ConfigLoader,
57
57
 
58
58
  CSD, CinCSD, SinCSD, DinCSD, // only use CSD, others for exposing methods (via IDE auto-suggestion)
59
59
 
package/jsconfig.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "compilerOptions": {
3
3
  "forceConsistentCasingInFileNames": true,
4
4
  "moduleResolution": "node",
5
- "target": "ES2017",
5
+ "target": "ES2022",
6
6
  "checkJs": true,
7
7
  "allowJs": true,
8
8
  "noEmit": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "binhend",
3
- "version": "2.3.7",
3
+ "version": "2.3.9",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "author": "Nguyen Duc Binh",
@@ -1,3 +1,4 @@
1
1
  module.exports = {
2
2
  ...require('./src/configuration'),
3
+ ...require('./src/process.env')
3
4
  };
@@ -0,0 +1,32 @@
1
+
2
+ const path = require('path');
3
+ const { cli } = require('./configuration').ConfigLoader;
4
+ const { String } = require('@binhend/validation');
5
+
6
+ function env(env = String(), rootPath = String()) {
7
+ rootPath = String(rootPath, { default: require.main.path });
8
+
9
+ const envExtension = typeof env === 'string' ? `.${env}` : '';
10
+ const configModuleFileName = `./env${envExtension}`;
11
+ const configModuleFilePath = path.resolve(rootPath, configModuleFileName);
12
+
13
+ try {
14
+ const localConfigs = require(configModuleFilePath);
15
+
16
+ for (var key in localConfigs) {
17
+ const value = localConfigs[key];
18
+ localConfigs[key] = typeof value === 'string' ? value : JSON.stringify(value);
19
+ }
20
+
21
+ return {
22
+ ...localConfigs,
23
+ ...process.env,
24
+ ...cli()
25
+ };
26
+ }
27
+ catch (error) {
28
+ throw new Error(`[BINHEND][CONFIG] Failed loading config from: ${configModuleFilePath}`, { cause: error });
29
+ }
30
+ };
31
+
32
+ module.exports = { env };
@@ -1,7 +1,7 @@
1
1
 
2
2
  class HttpError extends Error {
3
- constructor(httpCode, message) {
4
- super(message);
3
+ constructor(httpCode, message, options = {}) {
4
+ super(message, options);
5
5
  this.name = 'HttpError';
6
6
  this.httpCode = httpCode;
7
7
  }
@@ -1,7 +1,17 @@
1
1
 
2
- const HttpError = require('./HttpError');
2
+ function StatusCode(code = 500) {
3
+ /**
4
+ * Range of HTTP codes are from 100 to 599.
5
+ * HTTP code 500 is `Internal Server Error`.
6
+ */
7
+ return Number.isInteger(code) && code >= 100 && code <= 599 ? code : 500;
8
+ }
3
9
 
4
10
  module.exports = function (error, response, next) {
5
- if (!(error instanceof HttpError)) return next(error);
6
- response.status(error.httpCode || 500).json({ error: error.message || 'Internal Server Error' });
11
+ if (Object.prototype.hasOwnProperty.call(error, 'httpCode')) {
12
+ response.status(StatusCode(error.httpCode)).json({ error: error.message || 'Internal Server Error' });
13
+ }
14
+ else {
15
+ next(error);
16
+ }
7
17
  };
@@ -274,6 +274,44 @@ function Prop(key, object, validator, options) {
274
274
  });
275
275
  }
276
276
 
277
+ /**
278
+ * Return an object with all properties defined in the validator, using non-strict validation.
279
+ * Instead of throwing errors, invalid values are set to `null` by enforcing `{ default: null, required: false }` across all validations.
280
+ *
281
+ * @template V
282
+ * @param {((...args: any[]) => V)} [validator] - Validation function
283
+ * @returns {V} - An object with keys bypass requirement
284
+ * @throws {HttpError} - If validation fails
285
+ */
286
+ function DefaultObject(validator) {
287
+ OptionControl.default = null;
288
+ OptionControl.required = false;
289
+
290
+ try {
291
+ var value = validator();
292
+ return value;
293
+ }
294
+ catch (error) {
295
+ // TODO app log error for debug
296
+ throw new HttpError(HttpCodes.INTERNAL_SERVER_ERROR, `Type validation failed`);
297
+ }
298
+ finally {
299
+ delete OptionControl.default;
300
+ delete OptionControl.required;
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Returns an empty object as the validator output without performing any validation.
306
+ *
307
+ * @template V
308
+ * @param {((...args: any[]) => V)} [validator] - Validation function
309
+ * @returns {V} - An empty object with no property
310
+ */
311
+ function EmptyObject(validator) {
312
+ return /** @type {V} */ ({});
313
+ }
314
+
277
315
  /**
278
316
  * Validate an input being a function
279
317
  *
@@ -407,10 +445,12 @@ function NotNullish(input, options = {}) {
407
445
  /**
408
446
  * Generic validator that accepts a validation function
409
447
  *
410
- * @param {*} input - Input value needs to be validated.
448
+ * @template T
449
+ *
450
+ * @param {T} input - Input value needs to be validated.
411
451
  * @param {Function} validate - Validation function that returns boolean
412
452
  * @param {Options} options - Additional options for validation.
413
- * @returns {*} - The validated input
453
+ * @returns {T} - The validated input
414
454
  * @throws {HttpError} - If validation fails
415
455
  */
416
456
  function Validator(input, validate, options = {}) {
@@ -418,14 +458,22 @@ function Validator(input, validate, options = {}) {
418
458
  return input;
419
459
  }
420
460
 
421
- options = { ...options }; // prevent options being null
461
+ options = { ...options, ...OptionControl }; // prevent options being null
422
462
 
423
463
  // use default value (options.default - must also be valid) if has, when input is invalid
424
- if (options.hasOwnProperty('default') && validate(options.default)) {
425
- return options.default;
464
+ if (options.hasOwnProperty('default')) {
465
+ var defaultValue = options.default;
466
+
467
+ if (validate(defaultValue)) {
468
+ return defaultValue;
469
+ }
470
+
471
+ if (!options.required && types.isNullish(defaultValue)) {
472
+ return defaultValue;
473
+ }
426
474
  }
427
475
 
428
- // allow null or undefined by default, set `options.required=true` for not allowing
476
+ // accept `null` or `undefined` by default, set `options.required=true` for not accepting nullish values
429
477
  if (!options.required && types.isNullish(input)) {
430
478
  return input;
431
479
  }
@@ -443,6 +491,8 @@ function Validator(input, validate, options = {}) {
443
491
  }
444
492
  }
445
493
 
494
+ const OptionControl = {};
495
+
446
496
  module.exports = {
447
497
  String,
448
498
  Number,
@@ -453,6 +503,7 @@ module.exports = {
453
503
  PropIf, Prop,
454
504
  AssignIf, Assign,
455
505
  Value, Optional,
506
+ DefaultObject, EmptyObject,
456
507
  Function,
457
508
  AsyncFunction,
458
509
  Date,