xpref 1.0.0

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.
Files changed (61) hide show
  1. package/api-docs/body-schema.d.ts +1 -0
  2. package/api-docs/body-schema.js +31 -0
  3. package/api-docs/index.d.ts +3 -0
  4. package/api-docs/index.js +49 -0
  5. package/api-docs/parameter-schema.d.ts +1 -0
  6. package/api-docs/parameter-schema.js +57 -0
  7. package/api-docs/path-schema.d.ts +1 -0
  8. package/api-docs/path-schema.js +31 -0
  9. package/api-docs/path.d.ts +2 -0
  10. package/api-docs/path.js +79 -0
  11. package/api-docs/schema.d.ts +1 -0
  12. package/api-docs/schema.js +42 -0
  13. package/api-docs/security.d.ts +1 -0
  14. package/api-docs/security.js +48 -0
  15. package/api-docs/types.d.ts +27 -0
  16. package/api-docs/types.js +2 -0
  17. package/debug.d.ts +6 -0
  18. package/debug.js +26 -0
  19. package/i18n/index.d.ts +9 -0
  20. package/i18n/index.js +51 -0
  21. package/idempotency/index.d.ts +7 -0
  22. package/idempotency/index.js +130 -0
  23. package/idempotency/storage.d.ts +36 -0
  24. package/idempotency/storage.js +54 -0
  25. package/index.d.ts +7 -0
  26. package/index.js +126 -0
  27. package/package.json +36 -0
  28. package/request-forwarder/common.d.ts +11 -0
  29. package/request-forwarder/common.js +36 -0
  30. package/request-forwarder/forwarder.d.ts +2 -0
  31. package/request-forwarder/forwarder.js +81 -0
  32. package/request-forwarder/index.d.ts +2 -0
  33. package/request-forwarder/index.js +10 -0
  34. package/request-forwarder/pass-to-next.d.ts +4 -0
  35. package/request-forwarder/pass-to-next.js +48 -0
  36. package/request-forwarder/proxy.d.ts +8 -0
  37. package/request-forwarder/proxy.js +34 -0
  38. package/request-id.d.ts +7 -0
  39. package/request-id.js +19 -0
  40. package/request-log.d.ts +3 -0
  41. package/request-log.js +88 -0
  42. package/router.d.ts +13 -0
  43. package/router.js +65 -0
  44. package/setting/index.d.ts +1 -0
  45. package/setting/index.js +6 -0
  46. package/static.d.ts +2 -0
  47. package/static.js +12 -0
  48. package/types.d.ts +52 -0
  49. package/types.js +2 -0
  50. package/utils.d.ts +5 -0
  51. package/utils.js +22 -0
  52. package/validator/method-validator.d.ts +6 -0
  53. package/validator/method-validator.js +45 -0
  54. package/validator/route-schema.d.ts +2 -0
  55. package/validator/route-schema.js +71 -0
  56. package/validator/schema.d.ts +15 -0
  57. package/validator/schema.js +63 -0
  58. package/validator/validate.d.ts +8 -0
  59. package/validator/validate.js +94 -0
  60. package/validator/validator.test.d.ts +0 -0
  61. package/validator/validator.test.js +6 -0
package/router.js ADDED
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = registerRoutes;
4
+ const express_1 = require("express");
5
+ const getMethodHandlers = (handlerOptions, options = {}) => {
6
+ if (Array.isArray(handlerOptions))
7
+ return handlerOptions;
8
+ if (typeof handlerOptions === 'function')
9
+ return [handlerOptions];
10
+ const { action, params } = handlerOptions;
11
+ if (!(params || false))
12
+ return Array.isArray(action) ? action : [action];
13
+ const { validator } = options;
14
+ const validatorMiddleware = validator({ params });
15
+ const methodHandlers = Array.isArray(action) ? action : [action];
16
+ return [validatorMiddleware, ...methodHandlers];
17
+ };
18
+ /**
19
+ * Registers the verb handlers to routes
20
+ * @property {any} handlers
21
+ * @property {any} router
22
+ */
23
+ const registerHandler = ({ handlers, router }, options = {}) => {
24
+ const methods = Object.keys(handlers);
25
+ const path = '/';
26
+ methods.forEach((method) => {
27
+ const methodHandlers = handlers[method];
28
+ const callbacks = getMethodHandlers(methodHandlers, options);
29
+ router[method](path, ...callbacks);
30
+ });
31
+ };
32
+ /**
33
+ * Creates router for path information
34
+ * @param {PathDetail} pathDetail - The path default defined after uri
35
+ * @return router
36
+ */
37
+ const createRouter = (pathHandler, options) => {
38
+ const router = (0, express_1.Router)({ mergeParams: true });
39
+ const [_name, middlewares, handlers, children = {}] = pathHandler;
40
+ if (middlewares.length > 0)
41
+ router.use(...middlewares);
42
+ registerHandler({ handlers, router }, options);
43
+ const childPaths = Object.keys(children);
44
+ if (childPaths.length === 0)
45
+ return router;
46
+ childPaths.forEach((childPath) => {
47
+ const childRouter = createRouter(children[childPath], options);
48
+ router.use(childPath, childRouter);
49
+ });
50
+ return router;
51
+ };
52
+ /**
53
+ * Registers routes configuration, the way to register routes
54
+ * is based on route base, not url base
55
+ * @param {Application} app - Express Application
56
+ * @param {Route} routes - Routes configuration
57
+ */
58
+ function registerRoutes(app, routes, options) {
59
+ const paths = Object.keys(routes);
60
+ paths.forEach((path) => {
61
+ const pathDetail = routes[path];
62
+ const router = createRouter(pathDetail, options);
63
+ app.use(path, router);
64
+ });
65
+ }
@@ -0,0 +1 @@
1
+ export default function getSetting(): Date;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = getSetting;
4
+ function getSetting() {
5
+ return new Date();
6
+ }
package/static.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import { type Application } from 'express';
2
+ export default function registerStatic(app: Application, staticRoutes?: any): void;
package/static.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = registerStatic;
4
+ const path_1 = require("path");
5
+ const express_1 = require("express");
6
+ function registerStatic(app, staticRoutes = {}) {
7
+ const keys = Object.keys(staticRoutes);
8
+ keys.forEach((path) => {
9
+ const location = (0, path_1.resolve)(staticRoutes[path]);
10
+ app.use(path, (0, express_1.static)(location));
11
+ });
12
+ }
package/types.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ import type { Application } from 'express';
2
+ import type { IncomingMessage } from 'http';
3
+ export type { IncomingMessage } from 'http';
4
+ export type { Request, Response, NextFunction, Application } from 'express';
5
+ export type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
6
+ type MethodHandlerAction = CallableFunction | CallableFunction[];
7
+ type Params = {
8
+ query?: any;
9
+ path?: any;
10
+ body?: any;
11
+ };
12
+ export type MethodOptions = MethodHandlerAction | {
13
+ action: MethodHandlerAction;
14
+ params?: Params;
15
+ description?: string | [string, string];
16
+ };
17
+ export type MethodHandler = {
18
+ get?: MethodOptions;
19
+ post?: MethodOptions;
20
+ put?: MethodOptions;
21
+ delete?: MethodOptions;
22
+ patch?: MethodOptions;
23
+ };
24
+ export type PathMiddleware = Array<any>;
25
+ export type PathDetail = [string, PathMiddleware, MethodHandler] | [string, PathMiddleware, MethodHandler, Record<string, PathDetail>];
26
+ export type Route = Record<any, PathDetail>;
27
+ type OnInit = (_app: Application) => void;
28
+ export type API = {
29
+ appName: string;
30
+ appEnv: string;
31
+ port?: number;
32
+ routes: Route;
33
+ logger?: any;
34
+ staticRoutes?: Record<string, string>;
35
+ interceptor?: any;
36
+ onInit?: OnInit;
37
+ schemas?: Record<string, any>;
38
+ manuallyStart?: any;
39
+ };
40
+ export type RequestForwarder = {
41
+ host: string;
42
+ proxyPrefix?: string;
43
+ withPrefix?: boolean;
44
+ headers?: Record<string, string | boolean | number>;
45
+ onUrlConstructed?: (url: string) => string;
46
+ passToNext?: boolean;
47
+ };
48
+ export type ProxyResult = {
49
+ statusCode: number;
50
+ headers: IncomingMessage['headers'];
51
+ body: Buffer;
52
+ };
package/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/utils.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { Response } from 'express';
2
+ export declare const responseError: (res: Response, message: any, statusCode?: number) => Response<any, Record<string, any>>;
3
+ type DecodedSchema = [string, boolean, string[]];
4
+ export declare const decodeSchemaName: (schemaName: string, accuRequired?: string[]) => DecodedSchema;
5
+ export {};
package/utils.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decodeSchemaName = exports.responseError = void 0;
4
+ const responseError = (res, message, statusCode = 400) => {
5
+ const objMsg = typeof message === 'string' ? { message } : message;
6
+ const errorResult = {
7
+ error: true,
8
+ status: statusCode,
9
+ ...objMsg,
10
+ };
11
+ return res
12
+ .status(statusCode)
13
+ .send(errorResult);
14
+ };
15
+ exports.responseError = responseError;
16
+ const decodeSchemaName = (schemaName, accuRequired = []) => {
17
+ const [field, isRequired = false] = schemaName.split('*');
18
+ if (isRequired === false)
19
+ return [field, false, accuRequired];
20
+ return [field, true, [...accuRequired, field]];
21
+ };
22
+ exports.decodeSchemaName = decodeSchemaName;
@@ -0,0 +1,6 @@
1
+ import type { Request, Response, NextFunction, MethodOptions } from '../types';
2
+ type SchemaOptions = {
3
+ domainName?: string;
4
+ };
5
+ export default function initMethodValidation(pSchemas: any, options?: SchemaOptions): (methodOptions: MethodOptions) => (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
6
+ export {};
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = initMethodValidation;
7
+ const ajv_1 = __importDefault(require("ajv"));
8
+ const ajvErrors = require('ajv-errors');
9
+ const schema_1 = require("./schema");
10
+ const validate_1 = require("./validate");
11
+ const ajvOptions = {
12
+ allErrors: true,
13
+ $data: true,
14
+ strict: true,
15
+ coerceTypes: true,
16
+ schemas: [],
17
+ };
18
+ const ajv = new ajv_1.default(ajvOptions);
19
+ ajvErrors(ajv);
20
+ function initMethodValidation(pSchemas, options = {}) {
21
+ const { domainName = 'common' } = options;
22
+ const schemas = (0, schema_1.getObjectSchema)({
23
+ type: 'object',
24
+ properties: pSchemas,
25
+ required: [],
26
+ }, domainName);
27
+ ajv.addSchema(schemas);
28
+ return (methodOptions) => {
29
+ const sources = Object.keys(methodOptions);
30
+ return (req, res, next) => {
31
+ if (sources.length === 0)
32
+ return next();
33
+ const errors = (0, validate_1.validate)(ajv, {
34
+ methodOptions,
35
+ request: req,
36
+ });
37
+ if (errors.length === 0)
38
+ return next();
39
+ return res.status(400).json({
40
+ error: true,
41
+ errors: (0, validate_1.getErrors)(errors),
42
+ });
43
+ };
44
+ };
45
+ }
@@ -0,0 +1,2 @@
1
+ import type { MethodOptions } from '../types';
2
+ export default function getRouteSchema(methodOptions: Omit<MethodOptions, 'action'>): any;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = getRouteSchema;
4
+ const utils_1 = require("../utils");
5
+ const schema_1 = require("./schema");
6
+ const getSchemaFromString = (accu, refName) => {
7
+ const [accuProps, accuRequired] = accu;
8
+ const [schemaName, _re, required] = (0, utils_1.decodeSchemaName)(refName, accuRequired);
9
+ return [
10
+ { ...accuProps, [schemaName]: (0, schema_1.getRefSchema)(schemaName, 'common.js') },
11
+ required,
12
+ ];
13
+ };
14
+ const getSchemasOfArrayProps = (properties, required = []) => {
15
+ const result = properties.reduce((accu, prop) => {
16
+ const isString = typeof prop === 'string';
17
+ if (isString)
18
+ return getSchemaFromString(accu, prop);
19
+ const [accuProps, accuRequired] = accu;
20
+ const [name, props] = prop;
21
+ const [schemaName, _req, nextRequired] = (0, utils_1.decodeSchemaName)(name, accuRequired);
22
+ return [
23
+ { ...accuProps, [schemaName]: getObjectSchema(props) },
24
+ nextRequired,
25
+ ];
26
+ }, [{}, required]);
27
+ return result;
28
+ };
29
+ const getSchemasOfObjectProps = (properties, required = []) => {
30
+ const names = Object.keys(properties);
31
+ const result = names.reduce((accu) => accu, [{}, required]);
32
+ return result;
33
+ };
34
+ const injectId = (props, id = '') => {
35
+ if (id === '')
36
+ return props;
37
+ return { ...props, $id: id };
38
+ };
39
+ function getObjectSchema(schemaProps, id = '') {
40
+ const { type = 'string' } = schemaProps;
41
+ if (type !== 'object') {
42
+ const res = (0, schema_1.senitizeSchema)(schemaProps);
43
+ return res;
44
+ }
45
+ ;
46
+ const { properties = [], required = [] } = schemaProps;
47
+ const isArray = Array.isArray(properties);
48
+ const [nextProps, nextRequired] = (isArray)
49
+ ? getSchemasOfArrayProps(properties, required)
50
+ : getSchemasOfObjectProps(properties, required);
51
+ const result = { properties: nextProps, required: nextRequired, type: 'object' };
52
+ return injectId(result, id);
53
+ }
54
+ ;
55
+ function getRouteSchema(methodOptions) {
56
+ const { params = {} } = methodOptions;
57
+ return ['query', 'params', 'body'].reduce((accu, dataSlot) => {
58
+ const properties = params[dataSlot] || [];
59
+ const isArray = Array.isArray(properties);
60
+ const isEmpty = isArray && properties.length == 0;
61
+ if (isEmpty)
62
+ return accu;
63
+ const schemaProps = isArray
64
+ ? { properties, type: 'object' }
65
+ : { type: 'object', ...properties };
66
+ const now = new Date().getTime();
67
+ const schema = getObjectSchema(schemaProps, `${schema_1.domain}/${dataSlot}-${now}.js`);
68
+ return { ...accu, [dataSlot]: schema };
69
+ }, {});
70
+ }
71
+ ;
@@ -0,0 +1,15 @@
1
+ type ObjectSchema = {
2
+ type?: string;
3
+ properties: string[];
4
+ required?: string[];
5
+ $id?: string;
6
+ };
7
+ export declare const senitizeSchema: (schemaProps: Record<string, any>) => {
8
+ type: string;
9
+ };
10
+ export declare const domain = "https://schemas.api.com";
11
+ export declare const getRefSchema: (name: string, ref: string) => {
12
+ $ref: string;
13
+ };
14
+ export declare function getObjectSchema(schema: ObjectSchema, id?: string | false, ref?: string): ObjectSchema;
15
+ export {};
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRefSchema = exports.domain = exports.senitizeSchema = void 0;
4
+ exports.getObjectSchema = getObjectSchema;
5
+ const senitizeSchema = (schemaProps) => {
6
+ const { example: _ex, ...senitizedSchema } = schemaProps;
7
+ return { type: 'string', ...senitizedSchema };
8
+ };
9
+ exports.senitizeSchema = senitizeSchema;
10
+ exports.domain = 'https://schemas.api.com';
11
+ const getRef = (refName, ref = '') => `${ref}#/properties/${refName}`;
12
+ const getRefSchema = (name, ref) => ({
13
+ $ref: getRef(name, ref),
14
+ });
15
+ exports.getRefSchema = getRefSchema;
16
+ const getArrayProperties = (properties, ref = '') => {
17
+ if (properties.length === 0)
18
+ return properties;
19
+ const touchedProperties = properties.reduce((accu, prop) => {
20
+ const isString = typeof prop === 'string';
21
+ if (isString)
22
+ return { ...accu, [prop]: (0, exports.getRefSchema)(prop, ref) };
23
+ const [schemaName, schemaProps] = prop;
24
+ const type = schemaProps.type || 'string';
25
+ if (type !== 'object')
26
+ return {
27
+ ...accu,
28
+ [schemaName]: (0, exports.senitizeSchema)(schemaProps),
29
+ };
30
+ return {
31
+ ...accu,
32
+ [schemaName]: getObjectSchema(schemaProps),
33
+ };
34
+ }, {});
35
+ return touchedProperties;
36
+ };
37
+ const getObjectProperties = (properties) => {
38
+ const schemaNames = Object.keys(properties);
39
+ const nextProperties = schemaNames.reduce((accu, schemaName) => {
40
+ const schemaProps = properties[schemaName];
41
+ const type = schemaProps.type || 'string';
42
+ if (type !== 'object')
43
+ return { ...accu, [schemaName]: (0, exports.senitizeSchema)(schemaProps) };
44
+ return { ...accu, [schemaName]: getObjectSchema(schemaProps, false) };
45
+ }, {});
46
+ return nextProperties;
47
+ };
48
+ function getObjectSchema(schema, id = false, ref = '') {
49
+ const { properties, required = [] } = schema;
50
+ const isArray = Array.isArray(properties);
51
+ const nextProperties = isArray
52
+ ? getArrayProperties(properties, ref)
53
+ : getObjectProperties(properties);
54
+ const result = {
55
+ type: 'object',
56
+ properties: nextProperties,
57
+ required,
58
+ };
59
+ if (!id)
60
+ return result;
61
+ const refId = `${exports.domain}/${id}.js`;
62
+ return { ...result, $id: refId };
63
+ }
@@ -0,0 +1,8 @@
1
+ import type { Request, MethodOptions } from '../types';
2
+ type ValidationProps = {
3
+ request: Request;
4
+ methodOptions: MethodOptions;
5
+ };
6
+ export declare const getErrors: (errors: any) => any;
7
+ export declare const validate: (ajv: any, pProps: ValidationProps) => any;
8
+ export {};
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.validate = exports.getErrors = void 0;
7
+ const route_schema_1 = __importDefault(require("./route-schema"));
8
+ const anyOfRequiredField = [];
9
+ const caseToWords = (field) => field
10
+ .replace(/([a-z])([A-Z])/g, '$1 $2') // split camelCase => camel Case
11
+ .replace(/[_-]/g, ' ')
12
+ .replace(/\s+/g, ' ') // replace multi space with single one
13
+ .replace(/\b[a-z]/g, (char) => char.toUpperCase()) // capitalize text => Text
14
+ .trim(); // remove start/end space
15
+ const getRequestData = (req) => {
16
+ const { query, params, body } = req;
17
+ return { query, params, body };
18
+ };
19
+ const splitField = (field, delimiter = '/') => {
20
+ const fields = field.split(delimiter);
21
+ return fields[fields.length - 1];
22
+ };
23
+ const customMsg = (params, keyword, message) => {
24
+ const { missingProperty = '' } = params;
25
+ let newMsg = message;
26
+ switch (keyword) {
27
+ case 'required':
28
+ anyOfRequiredField.push(missingProperty);
29
+ const words = caseToWords(missingProperty);
30
+ newMsg = `${words} field is required.`;
31
+ break;
32
+ case 'anyOf':
33
+ newMsg = `Must has anyOf the field ${anyOfRequiredField}`;
34
+ anyOfRequiredField.splice(0, anyOfRequiredField.length);
35
+ break;
36
+ case 'maximum':
37
+ newMsg = message.replace('<=', 'less than or equal to');
38
+ break;
39
+ case 'minimum':
40
+ newMsg = message.replace('>=', 'greater than or equal to');
41
+ break;
42
+ case 'minLength':
43
+ newMsg = message.replace('NOT have fewer than', 'be at least');
44
+ break;
45
+ case 'enum':
46
+ newMsg = `${message} ${JSON.stringify(params.allowedValues)}`;
47
+ break;
48
+ default: break;
49
+ }
50
+ return newMsg;
51
+ };
52
+ const getErrorMsg = (error) => {
53
+ const { instancePath = '', params = {}, keyword = '', message, } = error;
54
+ const newMessage = customMsg(params, keyword, message);
55
+ if (instancePath === '')
56
+ return newMessage;
57
+ const errorField = splitField(instancePath, '/');
58
+ return `${caseToWords(errorField)} ${newMessage}`;
59
+ };
60
+ const getErrorField = (error) => {
61
+ const { params, keyword } = error;
62
+ switch (keyword) {
63
+ case 'required':
64
+ return splitField(params.missingProperty, '.');
65
+ case 'anyOf':
66
+ return 'anyOf';
67
+ default:
68
+ return splitField(error.instancePath, '/');
69
+ }
70
+ };
71
+ const getErrors = (errors) => (errors.reduce((acc, error) => {
72
+ const field = getErrorField(error);
73
+ const message = getErrorMsg(error);
74
+ return { ...acc, [field]: message };
75
+ }, {}));
76
+ exports.getErrors = getErrors;
77
+ const validate = (ajv, pProps) => {
78
+ const { methodOptions, request } = pProps;
79
+ const requestData = getRequestData(request);
80
+ const schemaData = (0, route_schema_1.default)(methodOptions);
81
+ const dataSlots = Object.keys(schemaData);
82
+ const validatedRequest = dataSlots.reduce((accu, dataSlot) => {
83
+ const schema = schemaData[dataSlot];
84
+ const data = requestData[dataSlot];
85
+ const ajvValidate = ajv.compile({ type: 'object', ...schema });
86
+ const valid = ajvValidate(data);
87
+ ajv.removeSchema(schema.$id);
88
+ if (valid)
89
+ return accu;
90
+ return [...accu, ...ajvValidate.errors];
91
+ }, []);
92
+ return validatedRequest;
93
+ };
94
+ exports.validate = validate;
File without changes
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ describe('Validator Test', () => {
3
+ it('Converts cany case to word', () => {
4
+ expect(1).toBe(1);
5
+ });
6
+ });