mock-config-server
Advanced tools
Comparing version 3.3.4 to 3.4.0
@@ -34,3 +34,3 @@ "use strict"; | ||
var _instance; | ||
(_instance = instance) === null || _instance === void 0 ? void 0 : _instance.destroy(); | ||
(_instance = instance) === null || _instance === void 0 || _instance.destroy(); | ||
}); | ||
@@ -37,0 +37,0 @@ build.onEnd(result => { |
@@ -1,1 +0,1 @@ | ||
export declare const cli: () => void; | ||
export declare const cli: () => Promise<void> | undefined; |
@@ -10,20 +10,29 @@ "use strict"; | ||
var _build = require("./build"); | ||
var _init = require("./init"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const initOptions = { | ||
baseUrl: { | ||
alias: 'b', | ||
description: 'Set base url for mock server', | ||
type: 'string' | ||
}, | ||
port: { | ||
alias: 'p', | ||
description: 'Set port for server', | ||
type: 'number' | ||
}, | ||
staticPath: { | ||
alias: 's', | ||
description: 'Set static path for mock server', | ||
type: 'string' | ||
} | ||
}; | ||
const cli = () => { | ||
const argv = (0, _yargs.default)((0, _helpers.hideBin)(process.argv)).usage('mcs [options]').epilogue('More info: https://github.com/siberiacancode/mock-config-server#readme').options({ | ||
baseUrl: { | ||
alias: 'b', | ||
description: 'Set base url for mock server', | ||
type: 'string' | ||
}, | ||
port: { | ||
alias: 'p', | ||
description: 'Set port for server', | ||
type: 'number' | ||
}, | ||
staticPath: { | ||
alias: 's', | ||
description: 'Set static path for mock server', | ||
type: 'string' | ||
}, | ||
const processArgv = (0, _helpers.hideBin)(process.argv); | ||
if (processArgv.includes('init')) { | ||
const argv = (0, _yargs.default)(processArgv).options(initOptions).parse(); | ||
return (0, _init.init)(argv); | ||
} | ||
const argv = (0, _yargs.default)(processArgv).usage('mcs [options]').epilogue('More info: https://github.com/siberiacancode/mock-config-server#readme').options({ | ||
...initOptions, | ||
config: { | ||
@@ -30,0 +39,0 @@ alias: 'c', |
@@ -0,3 +1,7 @@ | ||
export * from './createTemplate'; | ||
export * from './getMostSpecificPathFromError'; | ||
export * from './getValidationMessageFromPath'; | ||
export * from './isOnlyRequestedDataResolvingPropertyExists'; | ||
export * from './resolveConfigFile'; | ||
export * from './resolveConfigFilePath'; | ||
export * from './resolveExportsFromSourceCode'; |
@@ -6,2 +6,46 @@ "use strict"; | ||
}); | ||
var _createTemplate = require("./createTemplate"); | ||
Object.keys(_createTemplate).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _createTemplate[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _createTemplate[key]; | ||
} | ||
}); | ||
}); | ||
var _getMostSpecificPathFromError = require("./getMostSpecificPathFromError"); | ||
Object.keys(_getMostSpecificPathFromError).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _getMostSpecificPathFromError[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _getMostSpecificPathFromError[key]; | ||
} | ||
}); | ||
}); | ||
var _getValidationMessageFromPath = require("./getValidationMessageFromPath"); | ||
Object.keys(_getValidationMessageFromPath).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _getValidationMessageFromPath[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _getValidationMessageFromPath[key]; | ||
} | ||
}); | ||
}); | ||
var _isOnlyRequestedDataResolvingPropertyExists = require("./isOnlyRequestedDataResolvingPropertyExists"); | ||
Object.keys(_isOnlyRequestedDataResolvingPropertyExists).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _isOnlyRequestedDataResolvingPropertyExists[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _isOnlyRequestedDataResolvingPropertyExists[key]; | ||
} | ||
}); | ||
}); | ||
var _resolveConfigFile = require("./resolveConfigFile"); | ||
@@ -8,0 +52,0 @@ Object.keys(_resolveConfigFile).forEach(function (key) { |
#!/usr/bin/env node | ||
/// <reference types="node" /> | ||
import type { MockServerConfig, MockServerConfigArgv } from '../src'; | ||
export declare const run: (mockConfig: MockServerConfig, argv: MockServerConfigArgv) => (import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse> & { | ||
export declare const run: (mockConfig: MockServerConfig, { baseUrl, port, staticPath }: MockServerConfigArgv) => (import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse> & { | ||
destroy: (callback?: ((err?: Error | undefined) => void) | undefined) => import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>; | ||
}) | undefined; |
@@ -9,9 +9,30 @@ #!/usr/bin/env node | ||
var _server = require("../src/server"); | ||
var _helpers = require("../src/utils/helpers"); | ||
var _validateApiMockServerConfig = require("./validateMockServerConfig/validateApiMockServerConfig"); | ||
var _validateMockServerConfig = require("./validateMockServerConfig/validateMockServerConfig"); | ||
const run = (mockConfig, argv) => { | ||
const run = (mockConfig, { | ||
baseUrl, | ||
port, | ||
staticPath | ||
}) => { | ||
try { | ||
const mergedMockServerConfig = { | ||
...mockConfig, | ||
...argv | ||
baseUrl, | ||
port, | ||
staticPath | ||
}; | ||
if (!mergedMockServerConfig.rest && !mergedMockServerConfig.graphql && 'configs' in mergedMockServerConfig) { | ||
const mergedApiMockServerConfig = mergedMockServerConfig; | ||
if (Array.isArray(mergedApiMockServerConfig.configs) && (0, _helpers.isPlainObject)(mergedApiMockServerConfig.configs[0]) && 'path' in mergedApiMockServerConfig.configs[0]) { | ||
(0, _validateApiMockServerConfig.validateApiMockServerConfig)(mergedApiMockServerConfig, 'rest'); | ||
return (0, _server.startRestMockServer)(mergedApiMockServerConfig); | ||
} | ||
if (Array.isArray(mergedApiMockServerConfig.configs) && (0, _helpers.isPlainObject)(mergedApiMockServerConfig.configs[0]) && ('query' in mergedApiMockServerConfig.configs[0] || 'operationName' in mergedApiMockServerConfig.configs[0])) { | ||
(0, _validateApiMockServerConfig.validateApiMockServerConfig)(mergedApiMockServerConfig, 'graphql'); | ||
return (0, _server.startGraphQLMockServer)(mergedApiMockServerConfig); | ||
} | ||
(0, _validateApiMockServerConfig.validateApiMockServerConfig)(mergedApiMockServerConfig, 'rest'); | ||
return (0, _server.startRestMockServer)(mergedApiMockServerConfig); | ||
} | ||
(0, _validateMockServerConfig.validateMockServerConfig)(mergedMockServerConfig); | ||
@@ -18,0 +39,0 @@ return (0, _server.startMockServer)(mergedMockServerConfig); |
@@ -7,27 +7,34 @@ "use strict"; | ||
exports.validateMockServerConfig = void 0; | ||
var _validateBaseUrl = require("./validateBaseUrl/validateBaseUrl"); | ||
var _validateCors = require("./validateCors/validateCors"); | ||
var _validateDatabaseConfig = require("./validateDatabaseConfig/validateDatabaseConfig"); | ||
var _validateGraphqlConfig = require("./validateGraphqlConfig/validateGraphqlConfig"); | ||
var _validateInterceptors = require("./validateInterceptors/validateInterceptors"); | ||
var _validatePort = require("./validatePort/validatePort"); | ||
var _validateRestConfig = require("./validateRestConfig/validateRestConfig"); | ||
var _validateStaticPath = require("./validateStaticPath/validateStaticPath"); | ||
var _zod = require("zod"); | ||
var _helpers = require("../helpers"); | ||
var _baseUrlSchema = require("./baseUrlSchema/baseUrlSchema"); | ||
var _corsSchema = require("./corsSchema/corsSchema"); | ||
var _databaseConfigSchema = require("./databaseConfigSchema/databaseConfigSchema"); | ||
var _graphqlConfigSchema = require("./graphqlConfigSchema/graphqlConfigSchema"); | ||
var _interceptorsSchema = require("./interceptorsSchema/interceptorsSchema"); | ||
var _portSchema = require("./portSchema/portSchema"); | ||
var _restConfigSchema = require("./restConfigSchema/restConfigSchema"); | ||
var _staticPathSchema = require("./staticPathSchema/staticPathSchema"); | ||
var _utils = require("./utils"); | ||
const validateMockServerConfig = mockServerConfig => { | ||
if (!mockServerConfig.rest && !mockServerConfig.graphql && !mockServerConfig.database && !mockServerConfig.staticPath) { | ||
throw new Error('configuration should contain at least one of these configs: rest | graphql | database | staticPath; see our doc (https://www.npmjs.com/package/mock-config-server) for more information'); | ||
throw new Error('Configuration should contain at least one of these configs: rest | graphql | database | staticPath; see our doc (https://github.com/siberiacancode/mock-config-server) for more information'); | ||
} | ||
try { | ||
if (mockServerConfig.rest) (0, _validateRestConfig.validateRestConfig)(mockServerConfig.rest); | ||
if (mockServerConfig.graphql) (0, _validateGraphqlConfig.validateGraphqlConfig)(mockServerConfig.graphql); | ||
if (mockServerConfig.database) (0, _validateDatabaseConfig.validateDatabaseConfig)(mockServerConfig.database); | ||
(0, _validateBaseUrl.validateBaseUrl)(mockServerConfig.baseUrl); | ||
(0, _validatePort.validatePort)(mockServerConfig.port); | ||
(0, _validateStaticPath.validateStaticPath)(mockServerConfig.staticPath); | ||
(0, _validateInterceptors.validateInterceptors)(mockServerConfig.interceptors); | ||
(0, _validateCors.validateCors)(mockServerConfig.cors); | ||
} catch (error) { | ||
throw new Error(`Validation Error: configuration.${error.message} does not match the API schema. Click here to see correct type: https://github.com/siberiacancode/mock-config-server`); | ||
const mockServerConfigSchema = _zod.z.strictObject({ | ||
baseUrl: _baseUrlSchema.baseUrlSchema.optional(), | ||
port: _portSchema.portSchema.optional(), | ||
staticPath: _staticPathSchema.staticPathSchema.optional(), | ||
interceptors: (0, _utils.plainObjectSchema)(_interceptorsSchema.interceptorsSchema).optional(), | ||
cors: _corsSchema.corsSchema.optional(), | ||
rest: _restConfigSchema.restConfigSchema.optional(), | ||
graphql: _graphqlConfigSchema.graphqlConfigSchema.optional(), | ||
database: _databaseConfigSchema.databaseConfigSchema.optional() | ||
}); | ||
const validationResult = mockServerConfigSchema.safeParse(mockServerConfig); | ||
if (!validationResult.success) { | ||
const path = (0, _helpers.getMostSpecificPathFromError)(validationResult.error); | ||
const validationMessage = (0, _helpers.getValidationMessageFromPath)(path); | ||
throw new Error(`Validation Error: configuration${validationMessage} does not match the API schema. Click here to see correct type: https://github.com/siberiacancode/mock-config-server`); | ||
} | ||
}; | ||
exports.validateMockServerConfig = validateMockServerConfig; |
@@ -10,2 +10,3 @@ "use strict"; | ||
var _pagination = require("../pagination/pagination"); | ||
var _search = require("../search/search"); | ||
var _sort2 = require("../sort/sort"); | ||
@@ -17,17 +18,27 @@ const createNestedDatabaseRoutes = (router, database, storage) => { | ||
router.route(collectionPath).get((request, response) => { | ||
var _request$query; | ||
let data = storage.read(key); | ||
if (request.query && Object.keys(request.query).length) { | ||
const { | ||
_page, | ||
_limit, | ||
_begin, | ||
_end, | ||
_sort, | ||
_order, | ||
...filters | ||
} = request.query; | ||
if (!Array.isArray(data) || !request.query) { | ||
// ✅ important: | ||
// set 'Cache-Control' header for explicit browsers response revalidate | ||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control | ||
response.set('Cache-control', 'max-age=0, must-revalidate'); | ||
return response.json(data); | ||
} | ||
const { | ||
_page, | ||
_limit, | ||
_begin, | ||
_end, | ||
_sort, | ||
_order, | ||
_q, | ||
...filters | ||
} = request.query; | ||
if (Object.keys(filters).length) { | ||
data = (0, _filter.filter)(data, filters); | ||
} | ||
if ((_request$query = request.query) !== null && _request$query !== void 0 && _request$query._page) { | ||
if (_q) { | ||
data = (0, _search.search)(data, request.query._q); | ||
} | ||
if (_page) { | ||
data = (0, _pagination.pagination)(data, request.query); | ||
@@ -56,6 +67,6 @@ if (data._link) { | ||
} | ||
if (request.query && request.query._sort) { | ||
if (_sort) { | ||
data = (0, _sort2.sort)(data, request.query); | ||
} | ||
if (request.query._begin || request.query._end) { | ||
if (_begin || _end) { | ||
var _request$query$_begin; | ||
@@ -68,3 +79,3 @@ data = data.slice((_request$query$_begin = request.query._begin) !== null && _request$query$_begin !== void 0 ? _request$query$_begin : 0, request.query._end); | ||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control | ||
response.set('Cache-control', 'max-age=0, must-revalidate'); | ||
response.set('Cache-control', 'no-cache'); | ||
response.json(data); | ||
@@ -94,3 +105,3 @@ }); | ||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control | ||
response.set('Cache-control', 'max-age=0, must-revalidate'); | ||
response.set('Cache-control', 'no-cache'); | ||
response.json(storage.read([key, currentResourceIndex])); | ||
@@ -97,0 +108,0 @@ }); |
@@ -7,11 +7,72 @@ "use strict"; | ||
exports.createShallowDatabaseRoutes = void 0; | ||
var _filter = require("../filter/filter"); | ||
var _pagination = require("../pagination/pagination"); | ||
var _search = require("../search/search"); | ||
var _sort2 = require("../sort/sort"); | ||
const createShallowDatabaseRoutes = (router, database, storage) => { | ||
Object.keys(database).forEach(key => { | ||
const path = `/${key}`; | ||
router.route(path).get((_request, response) => { | ||
router.route(path).get((request, response) => { | ||
let data = storage.read(key); | ||
if (!Array.isArray(data) || !request.query) { | ||
// ✅ important: | ||
// set 'Cache-Control' header for explicit browsers response revalidate | ||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control | ||
response.set('Cache-control', 'no-cache'); | ||
return response.json(data); | ||
} | ||
data = data.filter(element => typeof element === 'object' && element !== null); | ||
const { | ||
_page, | ||
_limit, | ||
_begin, | ||
_end, | ||
_sort, | ||
_order, | ||
_q, | ||
...filters | ||
} = request.query; | ||
if (Object.keys(filters).length) { | ||
data = (0, _filter.filter)(data, filters); | ||
} | ||
if (_q) { | ||
data = (0, _search.search)(data, request.query._q); | ||
} | ||
if (_page) { | ||
data = (0, _pagination.pagination)(data, request.query); | ||
if (data._link) { | ||
const links = {}; | ||
const fullUrl = `${request.protocol}://${request.get('host')}${request.originalUrl}`; | ||
if (data._link.first) { | ||
links.first = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.first}`); | ||
} | ||
if (data._link.prev) { | ||
links.prev = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.prev}`); | ||
} | ||
if (data._link.next) { | ||
links.next = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.next}`); | ||
} | ||
if (data._link.last) { | ||
links.last = fullUrl.replace(`page=${data._link.current}`, `page=${data._link.last}`); | ||
} | ||
data._link = { | ||
...data._link, | ||
...links | ||
}; | ||
response.links(links); | ||
} | ||
} | ||
if (_sort) { | ||
data = (0, _sort2.sort)(data, request.query); | ||
} | ||
if (_begin || _end) { | ||
var _request$query$_begin; | ||
data = data.slice((_request$query$_begin = request.query._begin) !== null && _request$query$_begin !== void 0 ? _request$query$_begin : 0, request.query._end); | ||
response.set('X-Total-Count', data.length); | ||
} | ||
// ✅ important: | ||
// set 'Cache-Control' header for explicit browsers response revalidate | ||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control | ||
response.set('Cache-control', 'max-age=0, must-revalidate'); | ||
response.json(storage.read(key)); | ||
response.set('Cache-control', 'no-cache'); | ||
response.json(data); | ||
}); | ||
@@ -18,0 +79,0 @@ router.route(path).post((request, response) => { |
@@ -0,2 +1,3 @@ | ||
/// <reference types="node" /> | ||
import type { ParsedUrlQuery } from 'node:querystring'; | ||
export declare const filter: (array: any[], filters: ParsedUrlQuery) => any[]; |
@@ -8,11 +8,51 @@ "use strict"; | ||
var _flat = require("flat"); | ||
const filter = (array, filters) => array.filter(element => { | ||
const flattenedElement = (0, _flat.flatten)(element); | ||
return Object.entries(filters).every(([key, value]) => { | ||
if (Array.isArray(value)) { | ||
return value.includes(`${flattenedElement[key]}`); | ||
const OPERATORS = { | ||
neq: (a, b) => `${a}` !== `${b}`, | ||
gt: (a, b) => +a > +b, | ||
gte: (a, b) => +a >= +b, | ||
lt: (a, b) => +a < +b, | ||
lte: (a, b) => +a <= +b, | ||
cn: (a, b) => a.includes(b), | ||
ncn: (a, b) => !a.includes(b), | ||
sw: (a, b) => a.startsWith(b), | ||
nsw: (a, b) => !a.startsWith(b), | ||
ew: (a, b) => a.endsWith(b), | ||
new: (a, b) => !a.endsWith(b) | ||
}; | ||
const OPERATORS_KEYS = Object.keys(OPERATORS); | ||
const OPERATOR_REGEXP = new RegExp(`^(.+)_(${OPERATORS_KEYS.join('|')})$`); | ||
const getEntities = (object, key) => { | ||
const parts = key.match(OPERATOR_REGEXP); | ||
if (parts) { | ||
const [, element, operator] = parts; | ||
return { | ||
element: object[element], | ||
operator: operator | ||
}; | ||
} | ||
return { | ||
element: object[key] | ||
}; | ||
}; | ||
const filtered = (element, value, operator) => { | ||
if (!operator) return `${element}` === value; | ||
return OPERATORS[operator](element, value); | ||
}; | ||
const filter = (array, filters) => array.filter(arrayElement => { | ||
const flattenedArrayElement = (0, _flat.flatten)(arrayElement); | ||
return Object.entries(filters).every(([key, filter]) => { | ||
if (Array.isArray(filter)) { | ||
const { | ||
element, | ||
operator | ||
} = getEntities(flattenedArrayElement, key); | ||
return filter.some(value => filtered(element, value, operator)); | ||
} | ||
return `${flattenedElement[key]}` === value; | ||
const { | ||
element, | ||
operator | ||
} = getEntities(flattenedArrayElement, key); | ||
return filtered(element, filter, operator); | ||
}); | ||
}); | ||
exports.filter = filter; |
@@ -0,1 +1,2 @@ | ||
/// <reference types="node" /> | ||
import type { ParsedUrlQuery } from 'node:querystring'; | ||
@@ -2,0 +3,0 @@ export declare const pagination: (array: any[], queries: ParsedUrlQuery) => any[] | { |
@@ -0,2 +1,3 @@ | ||
/// <reference types="node" /> | ||
import type { ParsedUrlQuery } from 'node:querystring'; | ||
export declare const sort: (array: any[], queries: ParsedUrlQuery) => any[]; |
@@ -7,4 +7,3 @@ "use strict"; | ||
exports.sort = void 0; | ||
var _flat = _interopRequireDefault(require("flat")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var _flat = require("flat"); | ||
const DEFAULT_ORDER = 'asc'; | ||
@@ -16,4 +15,4 @@ const getOrder = order => { | ||
const sortArray = (array, key, order) => array.sort((a, b) => { | ||
const flattenedA = (0, _flat.default)(a); | ||
const flattenedB = (0, _flat.default)(b); | ||
const flattenedA = (0, _flat.flatten)(a); | ||
const flattenedB = (0, _flat.flatten)(b); | ||
if (!flattenedA[key] || !flattenedB[key]) return 0; | ||
@@ -20,0 +19,0 @@ if (typeof flattenedA[key] === 'string' && typeof flattenedB[key] === 'string') { |
@@ -25,3 +25,3 @@ "use strict"; | ||
var _this$nextDataPromise2; | ||
(_this$nextDataPromise2 = this.nextDataPromise) === null || _this$nextDataPromise2 === void 0 ? void 0 : _this$nextDataPromise2.then(() => { | ||
(_this$nextDataPromise2 = this.nextDataPromise) === null || _this$nextDataPromise2 === void 0 || _this$nextDataPromise2.then(() => { | ||
resolve(); | ||
@@ -45,3 +45,3 @@ }); | ||
var _this$nextDataResolve; | ||
(_this$nextDataResolve = this.nextDataResolve) === null || _this$nextDataResolve === void 0 ? void 0 : _this$nextDataResolve.call(this); | ||
(_this$nextDataResolve = this.nextDataResolve) === null || _this$nextDataResolve === void 0 || _this$nextDataResolve.call(this); | ||
this.nextDataPromise = null; | ||
@@ -48,0 +48,0 @@ this.nextDataResolve = null; |
@@ -17,3 +17,3 @@ "use strict"; | ||
const graphqlMiddleware = async (request, response, next) => { | ||
var _matchedRequestConfig, _matchedRouteConfig$s, _matchedRouteConfig$e, _matchedRouteConfig$i, _matchedRequestConfig2, _graphqlConfig$interc; | ||
var _matchedRequestConfig, _matchedRouteConfig$s, _matchedRouteConfig$e, _matchedRouteConfig$s2, _matchedRouteConfig$i, _matchedRequestConfig2, _graphqlConfig$interc, _matchedRouteConfig$s3; | ||
const graphQLInput = (0, _helpers.getGraphQLInput)(request); | ||
@@ -122,2 +122,10 @@ if (!graphQLInput.query) { | ||
const resolvedData = typeof matchedRouteConfigData === 'function' ? await matchedRouteConfigData(request, (_matchedRouteConfig$e = matchedRouteConfig.entities) !== null && _matchedRouteConfig$e !== void 0 ? _matchedRouteConfig$e : {}) : matchedRouteConfigData; | ||
if ((_matchedRouteConfig$s2 = matchedRouteConfig.settings) !== null && _matchedRouteConfig$s2 !== void 0 && _matchedRouteConfig$s2.status) { | ||
response.statusCode = matchedRouteConfig.settings.status; | ||
} | ||
// ✅ important: | ||
// set 'Cache-Control' header for explicit browsers response revalidate: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control | ||
// this code should place before response interceptors for giving opportunity to rewrite 'Cache-Control' header | ||
if (matchedRequestConfig.operationType === 'query') response.set('Cache-control', 'no-cache'); | ||
const data = await (0, _helpers.callResponseInterceptors)({ | ||
@@ -134,8 +142,6 @@ data: resolvedData, | ||
}); | ||
// ✅ important: | ||
// set 'Cache-Control' header for explicit browsers response revalidate | ||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control | ||
response.set('Cache-control', 'max-age=0, must-revalidate'); | ||
return response.status(response.statusCode).json(data); | ||
if ((_matchedRouteConfig$s3 = matchedRouteConfig.settings) !== null && _matchedRouteConfig$s3 !== void 0 && _matchedRouteConfig$s3.delay) { | ||
await (0, _helpers.sleep)(matchedRouteConfig.settings.delay); | ||
} | ||
return response.json(data); | ||
}; | ||
@@ -142,0 +148,0 @@ router.route('/').get((0, _helpers.asyncHandler)(graphqlMiddleware)); |
@@ -25,6 +25,12 @@ "use strict"; | ||
if ((0, _helpers.isPlainObject)(variables) && variables.checkMode) { | ||
// ✅ important: | ||
// check that actual value check modes does not have `value` for compare | ||
if (variables.checkMode === 'exists' || variables.checkMode === 'notExists') { | ||
routeConfigWeight += 1; | ||
return routeConfigWeight; | ||
} | ||
routeConfigWeight += (0, _helpers.isPlainObject)(variables.value) ? Object.keys(variables.value).length : 1; | ||
return routeConfigWeight; | ||
} | ||
routeConfigWeight += Object.keys(variables).length; | ||
routeConfigWeight += (0, _helpers.isPlainObject)(variables) ? Object.keys(variables).length : 1; | ||
} | ||
@@ -31,0 +37,0 @@ return routeConfigWeight; |
@@ -8,4 +8,6 @@ "use strict"; | ||
var _flat = require("flat"); | ||
var _path = _interopRequireDefault(require("path")); | ||
var _helpers = require("../../../utils/helpers"); | ||
var _helpers2 = require("./helpers"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const createRestRoutes = ({ | ||
@@ -18,3 +20,3 @@ router, | ||
router.route(requestConfig.path)[requestConfig.method]((0, _helpers.asyncHandler)(async (request, response, next) => { | ||
var _requestConfig$interc, _matchedRouteConfig$s, _matchedRouteConfig$e, _matchedRouteConfig$i, _requestConfig$interc2, _restConfig$intercept; | ||
var _requestConfig$interc, _matchedRouteConfig$s, _matchedRouteConfig$e, _matchedRouteConfig$s2, _matchedRouteConfig$i, _requestConfig$interc2, _restConfig$intercept, _matchedRouteConfig$s3; | ||
const requestInterceptor = (_requestConfig$interc = requestConfig.interceptors) === null || _requestConfig$interc === void 0 ? void 0 : _requestConfig$interc.request; | ||
@@ -38,6 +40,8 @@ if (requestInterceptor) { | ||
// ✅ important: check whole body as plain value strictly if descriptor used for body | ||
// ✅ important: | ||
// check whole body as plain value strictly if descriptor used for body | ||
const isEntityBodyByTopLevelDescriptor = entityName === 'body' && (0, _helpers.isEntityDescriptor)(entityDescriptorOrValue); | ||
if (isEntityBodyByTopLevelDescriptor) { | ||
// ✅ important: bodyParser sets body to empty object if body not sent or invalid, so assume {} as undefined | ||
// ✅ important: | ||
// bodyParser sets body to empty object if body not sent or invalid, so assume {} as undefined | ||
return (0, _helpers.resolveEntityValues)(checkMode, Object.keys(request.body).length ? request.body : undefined, descriptorValue); | ||
@@ -48,3 +52,4 @@ } | ||
return entityDescriptorOrValue.some(entityDescriptorOrValueElement => | ||
// ✅ important: bodyParser sets body to empty object if body not sent or invalid, so assume {} as undefined | ||
// ✅ important: | ||
// bodyParser sets body to empty object if body not sent or invalid, so assume {} as undefined | ||
(0, _helpers.resolveEntityValues)(checkMode, Object.keys(request.body).length ? request.body : undefined, entityDescriptorOrValueElement)); | ||
@@ -100,3 +105,14 @@ } | ||
} | ||
if ('file' in matchedRouteConfig) { | ||
if (!(0, _helpers.isFilePathValid)(matchedRouteConfig.file)) return next(); | ||
} | ||
const resolvedData = typeof matchedRouteConfigData === 'function' ? await matchedRouteConfigData(request, (_matchedRouteConfig$e = matchedRouteConfig.entities) !== null && _matchedRouteConfig$e !== void 0 ? _matchedRouteConfig$e : {}) : matchedRouteConfigData; | ||
if ((_matchedRouteConfig$s2 = matchedRouteConfig.settings) !== null && _matchedRouteConfig$s2 !== void 0 && _matchedRouteConfig$s2.status) { | ||
response.statusCode = matchedRouteConfig.settings.status; | ||
} | ||
// ✅ important: | ||
// set 'Cache-Control' header for explicit browsers response revalidate: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control | ||
// this code should place before response interceptors for giving opportunity to rewrite 'Cache-Control' header | ||
if (request.method === 'GET') response.set('Cache-control', 'no-cache'); | ||
const data = await (0, _helpers.callResponseInterceptors)({ | ||
@@ -113,8 +129,9 @@ data: resolvedData, | ||
}); | ||
// ✅ important: | ||
// set 'Cache-Control' header for explicit browsers response revalidate | ||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control | ||
response.set('Cache-control', 'max-age=0, must-revalidate'); | ||
return response.status(response.statusCode).json(data); | ||
if ((_matchedRouteConfig$s3 = matchedRouteConfig.settings) !== null && _matchedRouteConfig$s3 !== void 0 && _matchedRouteConfig$s3.delay) { | ||
await (0, _helpers.sleep)(matchedRouteConfig.settings.delay); | ||
} | ||
if ('file' in matchedRouteConfig) { | ||
return response.sendFile(_path.default.resolve(matchedRouteConfig.file)); | ||
} | ||
return response.json(data); | ||
})); | ||
@@ -121,0 +138,0 @@ }); |
@@ -27,2 +27,8 @@ "use strict"; | ||
if ((0, _helpers.isPlainObject)(body) && body.checkMode) { | ||
// ✅ important: | ||
// check that actual value check modes does not have `value` for compare | ||
if (body.checkMode === 'exists' || body.checkMode === 'notExists') { | ||
routeConfigWeight += 1; | ||
return routeConfigWeight; | ||
} | ||
routeConfigWeight += (0, _helpers.isPlainObject)(body.value) ? Object.keys(body.value).length : 1; | ||
@@ -29,0 +35,0 @@ return routeConfigWeight; |
@@ -54,3 +54,3 @@ "use strict"; | ||
graphqlConfig: { | ||
configs | ||
configs: configs !== null && configs !== void 0 ? configs : [] | ||
}, | ||
@@ -57,0 +57,0 @@ serverResponseInterceptor: interceptors === null || interceptors === void 0 ? void 0 : interceptors.response |
@@ -54,3 +54,3 @@ "use strict"; | ||
restConfig: { | ||
configs | ||
configs: configs !== null && configs !== void 0 ? configs : [] | ||
}, | ||
@@ -57,0 +57,0 @@ serverResponseInterceptor: interceptors === null || interceptors === void 0 ? void 0 : interceptors.response |
document.getElementById('scheme_switcher').addEventListener('click', () => window.switchScheme()); |
@@ -0,0 +0,0 @@ const lightStyles = document.querySelector( |
@@ -0,0 +0,0 @@ function switchTab(activeTabId) { |
@@ -7,3 +7,2 @@ "use strict"; | ||
exports.APP_PATH = void 0; | ||
const APP_PATH = process.cwd(); | ||
exports.APP_PATH = APP_PATH; | ||
const APP_PATH = exports.APP_PATH = process.cwd(); |
@@ -1,9 +0,8 @@ | ||
import type { CalculateByDescriptorValueCheckMode, CheckActualValueCheckMode, CheckMode, CompareWithDescriptorAnyValueCheckMode, CompareWithDescriptorStringValueCheckMode, CompareWithDescriptorValueCheckMode } from '../types'; | ||
export declare const CHECK_ACTUAL_VALUE_CHECK_MODES: CheckActualValueCheckMode[]; | ||
export declare const COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES: CompareWithDescriptorAnyValueCheckMode[]; | ||
export declare const COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES: CompareWithDescriptorStringValueCheckMode[]; | ||
export declare const COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES: CompareWithDescriptorValueCheckMode[]; | ||
export declare const CALCULATE_BY_DESCRIPTOR_VALUE_CHECK_MODES: CalculateByDescriptorValueCheckMode[]; | ||
export declare const CHECK_MODES: CheckMode[]; | ||
export declare const PLAIN_ENTITY_CHECK_MODES: CheckMode[]; | ||
export declare const NEGATION_CHECK_MODES: CheckMode[]; | ||
export declare const CHECK_ACTUAL_VALUE_CHECK_MODES: readonly ["exists", "notExists"]; | ||
export declare const COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES: readonly ["equals", "notEquals"]; | ||
export declare const COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES: readonly ["includes", "notIncludes", "startsWith", "notStartsWith", "endsWith", "notEndsWith"]; | ||
export declare const COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES: readonly ["equals", "notEquals", "includes", "notIncludes", "startsWith", "notStartsWith", "endsWith", "notEndsWith"]; | ||
export declare const CALCULATE_BY_DESCRIPTOR_VALUE_CHECK_MODES: readonly ["regExp", "function"]; | ||
export declare const CHECK_MODES: readonly ["exists", "notExists", "equals", "notEquals", "includes", "notIncludes", "startsWith", "notStartsWith", "endsWith", "notEndsWith", "regExp", "function"]; | ||
export declare const PLAIN_ENTITY_CHECK_MODES: readonly ["exists", "notExists", "equals", "notEquals", "function"]; | ||
export declare const NEGATION_CHECK_MODES: readonly ["notExists", "notEquals", "notIncludes", "notStartsWith", "notEndsWith"]; |
@@ -7,17 +7,9 @@ "use strict"; | ||
exports.PLAIN_ENTITY_CHECK_MODES = exports.NEGATION_CHECK_MODES = exports.COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES = exports.COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES = exports.COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES = exports.CHECK_MODES = exports.CHECK_ACTUAL_VALUE_CHECK_MODES = exports.CALCULATE_BY_DESCRIPTOR_VALUE_CHECK_MODES = void 0; | ||
const CHECK_ACTUAL_VALUE_CHECK_MODES = ['exists', 'notExists']; | ||
exports.CHECK_ACTUAL_VALUE_CHECK_MODES = CHECK_ACTUAL_VALUE_CHECK_MODES; | ||
const COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES = ['equals', 'notEquals']; | ||
exports.COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES = COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES; | ||
const COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES = ['includes', 'notIncludes', 'startsWith', 'notStartsWith', 'endsWith', 'notEndsWith']; | ||
exports.COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES = COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES; | ||
const COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES = [...COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES, ...COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES]; | ||
exports.COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES = COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES; | ||
const CALCULATE_BY_DESCRIPTOR_VALUE_CHECK_MODES = ['regExp', 'function']; | ||
exports.CALCULATE_BY_DESCRIPTOR_VALUE_CHECK_MODES = CALCULATE_BY_DESCRIPTOR_VALUE_CHECK_MODES; | ||
const CHECK_MODES = [...CHECK_ACTUAL_VALUE_CHECK_MODES, ...COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES, ...CALCULATE_BY_DESCRIPTOR_VALUE_CHECK_MODES]; | ||
exports.CHECK_MODES = CHECK_MODES; | ||
const PLAIN_ENTITY_CHECK_MODES = [...CHECK_ACTUAL_VALUE_CHECK_MODES, ...COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES, 'function']; | ||
exports.PLAIN_ENTITY_CHECK_MODES = PLAIN_ENTITY_CHECK_MODES; | ||
const NEGATION_CHECK_MODES = ['notExists', 'notEquals', 'notIncludes', 'notStartsWith', 'notEndsWith']; | ||
exports.NEGATION_CHECK_MODES = NEGATION_CHECK_MODES; | ||
const CHECK_ACTUAL_VALUE_CHECK_MODES = exports.CHECK_ACTUAL_VALUE_CHECK_MODES = ['exists', 'notExists']; | ||
const COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES = exports.COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES = ['equals', 'notEquals']; | ||
const COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES = exports.COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES = ['includes', 'notIncludes', 'startsWith', 'notStartsWith', 'endsWith', 'notEndsWith']; | ||
const COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES = exports.COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES = [...COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES, ...COMPARE_WITH_DESCRIPTOR_STRING_VALUE_CHECK_MODES]; | ||
const CALCULATE_BY_DESCRIPTOR_VALUE_CHECK_MODES = exports.CALCULATE_BY_DESCRIPTOR_VALUE_CHECK_MODES = ['regExp', 'function']; | ||
const CHECK_MODES = exports.CHECK_MODES = [...CHECK_ACTUAL_VALUE_CHECK_MODES, ...COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES, ...CALCULATE_BY_DESCRIPTOR_VALUE_CHECK_MODES]; | ||
const PLAIN_ENTITY_CHECK_MODES = exports.PLAIN_ENTITY_CHECK_MODES = [...CHECK_ACTUAL_VALUE_CHECK_MODES, ...COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES, 'function']; | ||
const NEGATION_CHECK_MODES = exports.NEGATION_CHECK_MODES = ['notExists', 'notEquals', 'notIncludes', 'notStartsWith', 'notEndsWith']; |
@@ -7,3 +7,3 @@ "use strict"; | ||
exports.DEFAULT = void 0; | ||
const DEFAULT = { | ||
const DEFAULT = exports.DEFAULT = { | ||
PORT: 31299, | ||
@@ -18,3 +18,2 @@ CORS: { | ||
} | ||
}; | ||
exports.DEFAULT = DEFAULT; | ||
}; |
export * from './asyncHandler'; | ||
export * from './config'; | ||
export * from './entities'; | ||
export * from './files'; | ||
export * from './graphql'; | ||
@@ -5,0 +6,0 @@ export * from './interceptors'; |
@@ -39,2 +39,13 @@ "use strict"; | ||
}); | ||
var _files = require("./files"); | ||
Object.keys(_files).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _files[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _files[key]; | ||
} | ||
}); | ||
}); | ||
var _graphql = require("./graphql"); | ||
@@ -41,0 +52,0 @@ Object.keys(_graphql).forEach(function (key) { |
import type { Request } from 'express'; | ||
import type { CheckActualValueCheckMode, CheckFunction, CheckMode, CompareWithDescriptorAnyValueCheckMode, CompareWithDescriptorValueCheckMode } from './checkModes'; | ||
import type { MappedEntity, PlainEntity } from './entities'; | ||
import type { Interceptors } from './interceptors'; | ||
import type { NestedObjectOrArray } from './utils'; | ||
import type { Data } from './values'; | ||
export type GraphQLEntityName = 'headers' | 'cookies' | 'query' | 'variables'; | ||
type GraphQLPlainEntityValue = string | number | boolean | null; | ||
type GraphQLMappedEntityValue = string | number | boolean; | ||
export type GraphQLTopLevelPlainEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: NestedObjectOrArray<GraphQLPlainEntityValue>, checkFunction: CheckFunction) => boolean; | ||
} : Check extends CompareWithDescriptorAnyValueCheckMode ? { | ||
checkMode: Check; | ||
value: NestedObjectOrArray<GraphQLPlainEntityValue>; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value?: never; | ||
} : never; | ||
type GraphQLPropertyLevelPlainEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: GraphQLPlainEntityValue | NestedObjectOrArray<GraphQLPlainEntityValue>, checkFunction: CheckFunction) => boolean; | ||
} : Check extends CompareWithDescriptorAnyValueCheckMode ? { | ||
checkMode: Check; | ||
value: GraphQLPlainEntityValue | NestedObjectOrArray<GraphQLPlainEntityValue>; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value?: never; | ||
} : never; | ||
type GraphQLMappedEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: GraphQLMappedEntityValue, checkFunction: CheckFunction) => boolean; | ||
} : Check extends 'regExp' ? { | ||
checkMode: Check; | ||
value: RegExp | RegExp[]; | ||
} : Check extends CompareWithDescriptorValueCheckMode ? { | ||
checkMode: Check; | ||
value: GraphQLMappedEntityValue | GraphQLMappedEntityValue[]; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value?: never; | ||
} : never; | ||
export type GraphQLEntityDescriptorOrValue<EntityName extends GraphQLEntityName = GraphQLEntityName> = EntityName extends 'variables' ? GraphQLTopLevelPlainEntityDescriptor | Record<string, GraphQLPropertyLevelPlainEntityDescriptor> | NestedObjectOrArray<GraphQLPlainEntityValue> : Record<string, GraphQLMappedEntityDescriptor | GraphQLMappedEntityValue | GraphQLMappedEntityValue[]>; | ||
export type GraphQLEntity<EntityName extends GraphQLEntityName = GraphQLEntityName> = EntityName extends 'variables' ? PlainEntity : MappedEntity; | ||
export type GraphQLOperationType = 'query' | 'mutation'; | ||
@@ -49,9 +13,11 @@ export type GraphQLOperationName = string | RegExp; | ||
export type GraphQLEntitiesByEntityName = { | ||
[EntityName in GraphQLEntityName]?: GraphQLEntityDescriptorOrValue<EntityName>; | ||
[EntityName in GraphQLEntityName]?: GraphQLEntity<EntityName>; | ||
}; | ||
type GraphQLSettings = { | ||
readonly polling: boolean; | ||
}; | ||
export type GraphQLRouteConfig<Settings extends GraphQLSettings = GraphQLSettings> = ({ | ||
settings: Settings & { | ||
interface GraphQLSettings { | ||
readonly polling?: boolean; | ||
readonly status?: number; | ||
readonly delay?: number; | ||
} | ||
export type GraphQLRouteConfig = ({ | ||
settings: GraphQLSettings & { | ||
polling: true; | ||
@@ -64,3 +30,3 @@ }; | ||
} | { | ||
settings?: Settings & { | ||
settings?: GraphQLSettings & { | ||
polling?: false; | ||
@@ -67,0 +33,0 @@ }; |
export * from './checkModes'; | ||
export * from './database'; | ||
export * from './entities'; | ||
export * from './graphql'; | ||
@@ -4,0 +5,0 @@ export * from './interceptors'; |
@@ -28,2 +28,13 @@ "use strict"; | ||
}); | ||
var _entities = require("./entities"); | ||
Object.keys(_entities).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
if (key in exports && exports[key] === _entities[key]) return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function () { | ||
return _entities[key]; | ||
} | ||
}); | ||
}); | ||
var _graphql = require("./graphql"); | ||
@@ -30,0 +41,0 @@ Object.keys(_graphql).forEach(function (key) { |
import type { Request } from 'express'; | ||
import type { CheckActualValueCheckMode, CheckFunction, CheckMode, CompareWithDescriptorAnyValueCheckMode, CompareWithDescriptorValueCheckMode } from './checkModes'; | ||
import type { MappedEntity, PlainEntity } from './entities'; | ||
import type { Interceptors } from './interceptors'; | ||
import type { NestedObjectOrArray } from './utils'; | ||
import type { Data } from './values'; | ||
export type RestMethod = 'get' | 'post' | 'delete' | 'put' | 'patch' | 'options'; | ||
export type RestEntityName = 'headers' | 'cookies' | 'query' | 'params' | 'body'; | ||
type RestPlainEntityValue = string | number | boolean | null; | ||
type RestMappedEntityValue = string | number | boolean; | ||
export type RestTopLevelPlainEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: NestedObjectOrArray<RestPlainEntityValue>, checkFunction: CheckFunction) => boolean; | ||
} : Check extends CompareWithDescriptorAnyValueCheckMode ? { | ||
checkMode: Check; | ||
value: NestedObjectOrArray<RestPlainEntityValue>; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value?: never; | ||
} : never; | ||
type RestPropertyLevelPlainEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: RestPlainEntityValue | NestedObjectOrArray<RestPlainEntityValue>, checkFunction: CheckFunction) => boolean; | ||
} : Check extends CompareWithDescriptorAnyValueCheckMode ? { | ||
checkMode: Check; | ||
value: RestPlainEntityValue | NestedObjectOrArray<RestPlainEntityValue>; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value?: never; | ||
} : never; | ||
type RestMappedEntityDescriptor<Check extends CheckMode = CheckMode> = Check extends 'function' ? { | ||
checkMode: Check; | ||
value: (actualValue: RestMappedEntityValue, checkFunction: CheckFunction) => boolean; | ||
} : Check extends 'regExp' ? { | ||
checkMode: Check; | ||
value: RegExp | RegExp[]; | ||
} : Check extends CompareWithDescriptorValueCheckMode ? { | ||
checkMode: Check; | ||
value: RestMappedEntityValue | RestMappedEntityValue[]; | ||
} : Check extends CheckActualValueCheckMode ? { | ||
checkMode: Check; | ||
value?: never; | ||
} : never; | ||
export type RestEntityDescriptorOrValue<EntityName extends RestEntityName = RestEntityName> = EntityName extends 'body' ? RestTopLevelPlainEntityDescriptor | Record<string, RestPropertyLevelPlainEntityDescriptor> | NestedObjectOrArray<RestPlainEntityValue> : Record<string, RestMappedEntityDescriptor | RestMappedEntityValue | RestMappedEntityValue[]>; | ||
export type RestEntity<EntityName extends RestEntityName = RestEntityName> = EntityName extends 'body' ? PlainEntity : MappedEntity; | ||
export type RestEntityNamesByMethod = { | ||
@@ -48,9 +12,11 @@ [key in RestMethod]: key extends 'get' | 'delete' | 'options' ? Exclude<RestEntityName, 'body'> : RestEntityName; | ||
export type RestEntitiesByEntityName<Method extends RestMethod = RestMethod> = { | ||
[EntityName in RestEntityNamesByMethod[Method]]?: RestEntityDescriptorOrValue<EntityName>; | ||
[EntityName in RestEntityNamesByMethod[Method]]?: RestEntity<EntityName>; | ||
}; | ||
interface RestSettings { | ||
readonly polling?: boolean; | ||
readonly status?: number; | ||
readonly delay?: number; | ||
} | ||
export type RestRouteConfig<Method extends RestMethod, Entities extends RestEntitiesByEntityName<Method> = RestEntitiesByEntityName<Method>, Settings extends RestSettings = RestSettings> = ({ | ||
settings: Settings & { | ||
export type RestRouteConfig<Method extends RestMethod> = ({ | ||
settings: RestSettings & { | ||
polling: true; | ||
@@ -60,11 +26,16 @@ }; | ||
time?: number; | ||
data: ((request: Request, entities: Entities) => Data | Promise<Data>) | Data; | ||
data: ((request: Request, entities: RestEntitiesByEntityName<Method>) => Data | Promise<Data>) | Data; | ||
}>; | ||
} | { | ||
settings?: Settings & { | ||
polling: false; | ||
settings?: RestSettings & { | ||
polling?: false; | ||
}; | ||
data: ((request: Request, entities: Entities) => Data | Promise<Data>) | Data; | ||
data: ((request: Request, entities: RestEntitiesByEntityName<Method>) => Data | Promise<Data>) | Data; | ||
} | { | ||
settings?: RestSettings & { | ||
polling?: false; | ||
}; | ||
file: string; | ||
}) & { | ||
entities?: Entities; | ||
entities?: RestEntitiesByEntityName<Method>; | ||
interceptors?: Pick<Interceptors, 'response'>; | ||
@@ -71,0 +42,0 @@ }; |
import type { Request } from 'express'; | ||
import type { Arguments } from 'yargs'; | ||
import type { GraphQLRequestConfig } from './graphql'; | ||
@@ -49,7 +50,7 @@ import type { Interceptors } from './interceptors'; | ||
export interface RestMockServerConfig extends BaseMockServerConfig { | ||
configs: RestRequestConfig[]; | ||
configs?: RestRequestConfig[]; | ||
database?: DatabaseConfig; | ||
} | ||
export interface GraphQLMockServerConfig extends BaseMockServerConfig { | ||
configs: GraphQLRequestConfig[]; | ||
configs?: GraphQLRequestConfig[]; | ||
database?: DatabaseConfig; | ||
@@ -61,3 +62,3 @@ } | ||
} | ||
export interface MockServerConfigArgv { | ||
export type MockServerConfigArgv = Arguments<{ | ||
baseUrl?: string; | ||
@@ -68,3 +69,3 @@ port?: number; | ||
watch?: boolean; | ||
} | ||
}>; | ||
export {}; |
{ | ||
"name": "mock-config-server", | ||
"version": "3.3.4", | ||
"version": "3.4.0", | ||
"description": "Tool that easily and quickly imitates server operation, create full fake api in few steps", | ||
@@ -25,2 +25,6 @@ "author": { | ||
"url": "https://github.com/anv296" | ||
}, | ||
{ | ||
"name": "Daria Bortsova", | ||
"url": "https://github.com/kvelian" | ||
} | ||
@@ -44,3 +48,3 @@ ], | ||
"build:types": "tsc -p tsconfig.production.json && tsc-alias -p tsconfig.production.json", | ||
"build:babel": "babel --delete-dir-on-start bin --out-dir dist/bin --extensions \".ts,.tsx\" && babel src --out-dir dist/src --extensions \".ts,.tsx\" --copy-files --no-copy-ignored && babel ./index.ts --out-dir dist --extensions \".ts\"", | ||
"build:babel": "babel --delete-dir-on-start bin --out-dir dist/bin --extensions .ts && shx cp -r bin/templates dist/bin/templates && babel --delete-dir-on-start src --out-dir dist/src --extensions .ts --copy-files --no-copy-ignored && babel ./index.ts --out-dir dist --extensions .ts", | ||
"build": "yarn build:babel && yarn build:types", | ||
@@ -69,11 +73,12 @@ "start": "yarn build && node ./dist/bin/bin.js", | ||
"dependencies": { | ||
"@types/body-parser": "^1.19.2", | ||
"@types/express": "^4.17.17", | ||
"@types/body-parser": "^1.19.5", | ||
"@types/express": "^4.17.21", | ||
"@types/flat": "^5.0.2", | ||
"@types/yargs": "^17.0.24", | ||
"@types/prompts": "^2.4.9", | ||
"@types/yargs": "^17.0.32", | ||
"ansi-colors": "^4.1.3", | ||
"body-parser": "^1.20.0", | ||
"body-parser": "^1.20.2", | ||
"ejs": "^3.1.9", | ||
"esbuild": "^0.18.17", | ||
"express": "^4.18.1", | ||
"esbuild": "^0.19.11", | ||
"express": "^4.18.2", | ||
"express-urlrewrite": "^2.0.1", | ||
@@ -83,23 +88,26 @@ "flat": "^5.0.2", | ||
"please-upgrade-node": "^3.2.0", | ||
"yargs": "^17.7.1" | ||
"prompts": "^2.4.2", | ||
"yargs": "^17.7.2", | ||
"zod": "^3.22.4" | ||
}, | ||
"devDependencies": { | ||
"@babel/cli": "^7.22.10", | ||
"@babel/core": "^7.22.10", | ||
"@babel/preset-env": "^7.22.10", | ||
"@babel/preset-typescript": "^7.22.5", | ||
"@siberiacancode/eslint": "^1.0.1", | ||
"@siberiacancode/jest": "^1.0.1", | ||
"@siberiacancode/prettier": "^1.0.0", | ||
"@siberiacancode/stylelint": "^1.0.1", | ||
"@types/jest": "^29.4.0", | ||
"@types/supertest": "^2.0.12", | ||
"husky": "^8.0.1", | ||
"lint-staged": "^13.1.1", | ||
"nodemon": "^3.0.1", | ||
"style-loader": "^3.3.2", | ||
"supertest": "^6.3.3", | ||
"ts-jest": "^29.0.3", | ||
"tsc-alias": "^1.8.5", | ||
"typescript": "^5.1.6" | ||
"@babel/cli": "^7.23.4", | ||
"@babel/core": "^7.23.7", | ||
"@babel/preset-env": "^7.23.8", | ||
"@babel/preset-typescript": "^7.23.3", | ||
"@siberiacancode/eslint": "^1.0.3", | ||
"@siberiacancode/jest": "^1.0.2", | ||
"@siberiacancode/prettier": "^1.0.1", | ||
"@siberiacancode/stylelint": "^1.0.2", | ||
"@types/jest": "^29.5.11", | ||
"@types/supertest": "^6.0.2", | ||
"husky": "^8.0.3", | ||
"lint-staged": "^15.2.0", | ||
"nodemon": "^3.0.3", | ||
"shx": "^0.3.4", | ||
"style-loader": "^3.3.4", | ||
"supertest": "^6.3.4", | ||
"ts-jest": "^29.1.1", | ||
"tsc-alias": "^1.8.8", | ||
"typescript": "^5.3.3" | ||
}, | ||
@@ -106,0 +114,0 @@ "homepage": "https://github.com/siberiacancode/mock-config-server", |
110
README.md
@@ -91,6 +91,11 @@ # 🎉 Mock Config Server | ||
Every route must be configured to handle response content in one of three ways: data or [queue](#polling) or [file](#file-responses). | ||
- `path` {string | RegExp} request path | ||
- `method` {GET | POST | DELETE | PUT | PATCH} rest api method | ||
- `method` {get | post | delete | put | patch | options} rest api method | ||
- `routes` {RestRouteConfig[]} request routes | ||
- `data` {any} mock data of request | ||
- `data?` {any} mock data of request | ||
- `queue?` {Array<{ time?: number; data: any}>} queue for polling with opportunity to set time for each response | ||
- `file?` {string} path to file for return in response | ||
- `settings?` {Settings} settings for route (polling on/off, etc.) | ||
- `entities?` Object<headers | cookies | query | params | body> object that helps in data retrieval | ||
@@ -102,2 +107,4 @@ - `interceptors?` {Interceptors} functions to change request or response parameters, [read](#interceptors) | ||
Every route must be configured to handle response content in one of two ways: data or [queue](#polling). | ||
- `operationType` {query | mutation} graphql operation type | ||
@@ -107,3 +114,5 @@ - `operationName?` {string | RegExp} graphql operation name | ||
- `routes` {GraphQLRouteConfig[]} request routes | ||
- `data` {any} mock data of request | ||
- `data?` {any} mock data of request | ||
- `queue?` {Array<{ time?: number; data: any}>} queue for polling with opportunity to set time for each response | ||
- `settings?` {Settings} settings for route (polling on/off, etc.) | ||
- `entities?` Object<headers | cookies | query | variables> object that helps in data retrieval | ||
@@ -479,2 +488,62 @@ - `interceptors?` {Interceptors} functions to change request or response parameters, [read](#interceptors) | ||
#### File responses | ||
Rest routes support paths to files. If a route is matched, the server will send data from the file. If the file is not found, the server will return 404. | ||
```javascript | ||
/** @type {import('mock-config-server').MockServerConfig} */ | ||
const mockServerConfig = { | ||
rest: { | ||
baseUrl: '/api', | ||
configs: [ | ||
{ | ||
path: '/files/settings', | ||
method: 'get', | ||
routes: [ | ||
{ | ||
file: './settings.json' | ||
} | ||
] | ||
} | ||
] | ||
} | ||
}; | ||
export default mockServerConfig; | ||
``` | ||
> If the file path is absolute, then this path will be used as is. If the file path is relative, it will be appended to the current working directory. | ||
If the file exists, response interceptors will receive null as the data argument. | ||
```javascript | ||
/** @type {import('mock-config-server').MockServerConfig} */ | ||
const mockServerConfig = { | ||
rest: { | ||
baseUrl: '/api', | ||
configs: [ | ||
{ | ||
path: '/files/settings', | ||
method: 'get', | ||
routes: [ | ||
{ | ||
file: './settings.json', | ||
interceptors: { | ||
response: (data) => { | ||
console.log(data); // null | ||
return data; | ||
} | ||
} | ||
} | ||
] | ||
} | ||
] | ||
} | ||
}; | ||
export default mockServerConfig; | ||
``` | ||
> Any changes to the data will not affect the file (and the response, respectively). | ||
#### Static Path | ||
@@ -704,2 +773,16 @@ | ||
### Full text search | ||
> Add \_q parameter for search data, search can be done by strings and numbers | ||
``` | ||
GET /users?_q=siberia | ||
``` | ||
For multiple search | ||
``` | ||
GET /users?_q=siberia&_q=24 | ||
``` | ||
### File example | ||
@@ -738,2 +821,14 @@ | ||
# Init Command | ||
The init command is used to initialize a new project or set up the initial configuration for a tool. It helps users get started with a new project by providing a streamlined setup process. | ||
``` | ||
mcs init | ||
Examples: | ||
mcs init | ||
mcs init --baseurl /base/url --port 3000 | ||
``` | ||
## ✨ Contributors | ||
@@ -779,3 +874,12 @@ | ||
</td> | ||
<td align="center" style="word-wrap: break-word; width: 100.0; height: 100.0"> | ||
<a href="https://github.com/kvelian"> | ||
<img src="https://avatars.githubusercontent.com/u/81089091?s=400&u=7c4fcc6d120f4b13ccbd03a9a384622b6523c376&v=4" | ||
width="100;" | ||
alt="kvelian" /> | ||
<br /> | ||
<sub style="font-size:13px"><b>🌵 kvelian</b></sub> | ||
</a> | ||
</td> | ||
</tr> | ||
</table> |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
352137
320
6774
879
17
19
6
+ Added@types/prompts@^2.4.9
+ Addedprompts@^2.4.2
+ Addedzod@^3.22.4
+ Added@esbuild/aix-ppc64@0.19.12(transitive)
+ Added@esbuild/android-arm@0.19.12(transitive)
+ Added@esbuild/android-arm64@0.19.12(transitive)
+ Added@esbuild/android-x64@0.19.12(transitive)
+ Added@esbuild/darwin-arm64@0.19.12(transitive)
+ Added@esbuild/darwin-x64@0.19.12(transitive)
+ Added@esbuild/freebsd-arm64@0.19.12(transitive)
+ Added@esbuild/freebsd-x64@0.19.12(transitive)
+ Added@esbuild/linux-arm@0.19.12(transitive)
+ Added@esbuild/linux-arm64@0.19.12(transitive)
+ Added@esbuild/linux-ia32@0.19.12(transitive)
+ Added@esbuild/linux-loong64@0.19.12(transitive)
+ Added@esbuild/linux-mips64el@0.19.12(transitive)
+ Added@esbuild/linux-ppc64@0.19.12(transitive)
+ Added@esbuild/linux-riscv64@0.19.12(transitive)
+ Added@esbuild/linux-s390x@0.19.12(transitive)
+ Added@esbuild/linux-x64@0.19.12(transitive)
+ Added@esbuild/netbsd-x64@0.19.12(transitive)
+ Added@esbuild/openbsd-x64@0.19.12(transitive)
+ Added@esbuild/sunos-x64@0.19.12(transitive)
+ Added@esbuild/win32-arm64@0.19.12(transitive)
+ Added@esbuild/win32-ia32@0.19.12(transitive)
+ Added@esbuild/win32-x64@0.19.12(transitive)
+ Added@types/prompts@2.4.9(transitive)
+ Addedesbuild@0.19.12(transitive)
+ Addedkleur@3.0.3(transitive)
+ Addedprompts@2.4.2(transitive)
+ Addedsisteransi@1.0.5(transitive)
+ Addedzod@3.24.2(transitive)
- Removed@esbuild/android-arm@0.18.20(transitive)
- Removed@esbuild/android-arm64@0.18.20(transitive)
- Removed@esbuild/android-x64@0.18.20(transitive)
- Removed@esbuild/darwin-arm64@0.18.20(transitive)
- Removed@esbuild/darwin-x64@0.18.20(transitive)
- Removed@esbuild/freebsd-arm64@0.18.20(transitive)
- Removed@esbuild/freebsd-x64@0.18.20(transitive)
- Removed@esbuild/linux-arm@0.18.20(transitive)
- Removed@esbuild/linux-arm64@0.18.20(transitive)
- Removed@esbuild/linux-ia32@0.18.20(transitive)
- Removed@esbuild/linux-loong64@0.18.20(transitive)
- Removed@esbuild/linux-mips64el@0.18.20(transitive)
- Removed@esbuild/linux-ppc64@0.18.20(transitive)
- Removed@esbuild/linux-riscv64@0.18.20(transitive)
- Removed@esbuild/linux-s390x@0.18.20(transitive)
- Removed@esbuild/linux-x64@0.18.20(transitive)
- Removed@esbuild/netbsd-x64@0.18.20(transitive)
- Removed@esbuild/openbsd-x64@0.18.20(transitive)
- Removed@esbuild/sunos-x64@0.18.20(transitive)
- Removed@esbuild/win32-arm64@0.18.20(transitive)
- Removed@esbuild/win32-ia32@0.18.20(transitive)
- Removed@esbuild/win32-x64@0.18.20(transitive)
- Removedesbuild@0.18.20(transitive)
Updated@types/body-parser@^1.19.5
Updated@types/express@^4.17.21
Updated@types/yargs@^17.0.32
Updatedbody-parser@^1.20.2
Updatedesbuild@^0.19.11
Updatedexpress@^4.18.2
Updatedyargs@^17.7.2