mockapi-msi 2.0.1 → 2.5.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.
@@ -1,31 +1,9 @@
1
- function HttpException(httpStatusCode, message) {
2
- var instance = new Error(message);
3
-
4
- instance.name = 'HttpException';
5
- instance.httpStatusCode = httpStatusCode;
6
-
7
- Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
8
-
9
- if (Error.captureStackTrace) {
10
- Error.captureStackTrace(instance, HttpException);
11
- }
12
-
13
- return instance;
14
- }
15
-
16
- HttpException.prototype = Object.create(Error.prototype, {
17
- constructor: {
18
- value: Error,
19
- enumerable: false,
20
- writable: true,
21
- configurable: true
22
- }
23
- });
24
-
25
- if (Object.setPrototypeOf){
26
- Object.setPrototypeOf(HttpException, Error);
27
- } else {
28
- HttpException.__proto__ = Error;
29
- }
30
-
1
+ class HttpException extends Error {
2
+ constructor(httpStatusCode, message) {
3
+ super(message);
4
+ this.name = 'HttpException';
5
+ this.httpStatusCode = httpStatusCode;
6
+ }
7
+ }
8
+
31
9
  module.exports = HttpException;
@@ -0,0 +1,22 @@
1
+ const constants = require('./constants');
2
+
3
+ const { fgCyan, fgGreen, fgYellow, fgMagenta, reset } = constants.COLOR;
4
+
5
+
6
+ const banner = [
7
+ `${fgCyan}$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$$\\ $$$$$$\\ ${reset}`,
8
+ `${fgCyan}$$$\\ $$$ | $$ | $$ __$$\\ $$ __$$\\\\_$$ _|${reset}`,
9
+ `${fgCyan}$$$$\\ $$$$ | $$$$$$\\ $$$$$$$\\ $$ | $$\\ $$ / $$ |$$ | $$ | $$ | ${reset}`,
10
+ `${fgGreen}$$\\$$\\$$ $$ |$$ __$$\\ $$ _____|$$ | $$ |$$$$$$$$ |$$$$$$$ | $$ | ${reset}`,
11
+ `${fgGreen}$$ \\$$$ $$ |$$ / $$ |$$ / $$$$$$ / $$ __$$ |$$ ____/ $$ | ${reset}`,
12
+ `${fgGreen}$$ |\\$ /$$ |$$ | $$ |$$ | $$ _$$< $$ | $$ |$$ | $$ | ${reset}`,
13
+ `${fgMagenta}$$ | \\_/ $$ |\\$$$$$$ |\\$$$$$$$\\ $$ | \\$$\\ $$ | $$ |$$ | $$$$$$\\ ${reset}`,
14
+ `${fgMagenta}\\__| \\__| \\______/ \\_______|\\__| \\__|\\__| \\__|\\__| \\______|${reset}`,
15
+ ];
16
+
17
+ const display = () => {
18
+ banner.forEach(line => console.log(line));
19
+ console.log('');
20
+ };
21
+
22
+ module.exports = { display };
package/modules/cli.js CHANGED
@@ -1,107 +1,110 @@
1
- const readline = require('readline');
2
- const YAML = require('yaml');
3
- const fs = require('fs');
4
-
5
- class CLI {
6
-
7
- _configurationFilePath = "";
8
- _arguments = [];
9
- _commands = {
10
- "--help": this._helpCommand,
11
- "help": this._helpCommand,
12
- "init": this._initCommand,
13
- "--init": this._initCommand
14
- };
15
- _configTemplate = {
16
- port: 8080,
17
- enableCors: true,
18
- data: {
19
- myRows: { path: 'YOUR FOLDER', reader: 'folder' }
20
- },
21
- endpoints: {
22
- '/data': {
23
- verb: 'get',
24
- data: 'myRows',
25
- responseStatus: 200,
26
- responseContentType: 'application/json'
27
- }
28
- },
29
- log: 'verbose'
30
- };
31
-
32
- constructor(configurationFilePath) {
33
- this._configurationFilePath = configurationFilePath;
34
- this._arguments = process.argv.slice(2);
35
- }
36
-
37
- _initCommand() {
38
- let configTemplate = this._configTemplate;
39
-
40
- const rl = readline.createInterface({
41
- input: process.stdin,
42
- output: process.stdout
43
- });
44
-
45
- console.log("Creating a basic configuration file");
46
- console.log("");
47
-
48
- rl.question(`Set MockAPI listening port (8080): `, (port) => {
49
- rl.question(`Do you want to enable CORS? Y/n: `, (enableCors) => {
50
- rl.question(`Do you want to include default endpoint? Y/n: `, (defaultEndpoint) => {
51
- const configPort = port || 8080;
52
- const configEnableCors = enableCors === "Y" || enableCors === "y" || enableCors === "";
53
- const configDefaultEndpoint = defaultEndpoint === "Y" || defaultEndpoint === "y" || defaultEndpoint === "";
54
-
55
- configTemplate.port = configPort;
56
- configTemplate.enableCors = configEnableCors;
57
-
58
- if (configDefaultEndpoint === false) {
59
- delete configTemplate.endpoints;
60
- delete configTemplate.data;
61
- }
62
-
63
- const configFile = YAML.stringify(configTemplate);
64
-
65
- fs.writeFile(this._configurationFilePath, configFile, (err) => {
66
- if (err) {
67
- console.log(err);
68
- } else {
69
- console.log("Configuration file created");
70
- }
71
- });
72
-
73
- rl.close();
74
- });
75
- });
76
- });
77
-
78
- }
79
-
80
- _helpCommand() {
81
- console.log("Run MockAPI:");
82
- console.log("mockapi\n");
83
- console.log("Command execution:\n");
84
- console.log("mockapi <command>");
85
- console.log("");
86
- console.log("--help, help shows this help");
87
- console.log("--init, init creates a basic configuration file");
88
- console.log("");
89
- }
90
-
91
- hasCommands() { return this._arguments.length > 0; }
92
-
93
- executeCommandLine() {
94
- if (this._arguments.length > 0) {
95
-
96
- let command = this._commands["--help"];
97
-
98
- if (this._commands[this._arguments[0]] !== undefined) {
99
- command = this._commands[this._arguments[0]];
100
- }
101
-
102
- command.apply(this);
103
- }
104
- }
105
- }
106
-
107
- module.exports = CLI;
1
+ const readline = require('readline');
2
+ const YAML = require('yaml');
3
+ const fs = require('fs');
4
+
5
+ class CLI {
6
+
7
+ _configurationFilePath = "";
8
+ _arguments = [];
9
+ _commands = {
10
+ "--help": this._helpCommand,
11
+ "help": this._helpCommand,
12
+ "init": this._initCommand,
13
+ "--init": this._initCommand
14
+ };
15
+ _configTemplate = {
16
+ port: 8080,
17
+ enableCors: true,
18
+ openApi: {
19
+ enabled: true
20
+ },
21
+ data: {
22
+ myRows: { path: 'YOUR FOLDER', reader: 'folder' }
23
+ },
24
+ endpoints: {
25
+ '/data': {
26
+ verb: 'get',
27
+ data: 'myRows',
28
+ responseStatus: 200,
29
+ responseContentType: 'application/json'
30
+ }
31
+ },
32
+ log: 'verbose'
33
+ };
34
+
35
+ constructor(configurationFilePath) {
36
+ this._configurationFilePath = configurationFilePath;
37
+ this._arguments = process.argv.slice(2);
38
+ }
39
+
40
+ _initCommand() {
41
+ let configTemplate = this._configTemplate;
42
+
43
+ const rl = readline.createInterface({
44
+ input: process.stdin,
45
+ output: process.stdout
46
+ });
47
+
48
+ console.log("Creating a basic configuration file");
49
+ console.log("");
50
+
51
+ rl.question(`Set MockAPI listening port (8080): `, (port) => {
52
+ rl.question(`Do you want to enable CORS? Y/n: `, (enableCors) => {
53
+ rl.question(`Do you want to include default endpoint? Y/n: `, (defaultEndpoint) => {
54
+ const configPort = port || 8080;
55
+ const configEnableCors = enableCors === "Y" || enableCors === "y" || enableCors === "";
56
+ const configDefaultEndpoint = defaultEndpoint === "Y" || defaultEndpoint === "y" || defaultEndpoint === "";
57
+
58
+ configTemplate.port = configPort;
59
+ configTemplate.enableCors = configEnableCors;
60
+
61
+ if (configDefaultEndpoint === false) {
62
+ delete configTemplate.endpoints;
63
+ delete configTemplate.data;
64
+ }
65
+
66
+ const configFile = YAML.stringify(configTemplate);
67
+
68
+ fs.writeFile(this._configurationFilePath, configFile, (err) => {
69
+ if (err) {
70
+ console.log(err);
71
+ } else {
72
+ console.log("Configuration file created");
73
+ }
74
+ });
75
+
76
+ rl.close();
77
+ });
78
+ });
79
+ });
80
+
81
+ }
82
+
83
+ _helpCommand() {
84
+ console.log("Run MockAPI:");
85
+ console.log("mockapi\n");
86
+ console.log("Command execution:\n");
87
+ console.log("mockapi <command>");
88
+ console.log("");
89
+ console.log("--help, help shows this help");
90
+ console.log("--init, init creates a basic configuration file");
91
+ console.log("");
92
+ }
93
+
94
+ hasCommands() { return this._arguments.length > 0; }
95
+
96
+ executeCommandLine() {
97
+ if (this._arguments.length > 0) {
98
+
99
+ let command = this._commands["--help"];
100
+
101
+ if (this._commands[this._arguments[0]] !== undefined) {
102
+ command = this._commands[this._arguments[0]];
103
+ }
104
+
105
+ command.apply(this);
106
+ }
107
+ }
108
+ }
109
+
110
+ module.exports = CLI;
@@ -0,0 +1,60 @@
1
+ const fs = require('fs');
2
+ const YAML = require('yaml');
3
+ const readers = require('./readers');
4
+
5
+ class ConfigWatcher {
6
+
7
+ _filePath = '';
8
+ _logger = null;
9
+ _onChange = null;
10
+ _watcher = null;
11
+ _debounceTimer = null;
12
+
13
+ constructor(filePath, logger, onChange) {
14
+ this._filePath = filePath;
15
+ this._logger = logger;
16
+ this._onChange = onChange;
17
+ }
18
+
19
+ watch() {
20
+ this._logger.info(`Watching configuration file for changes: ${this._filePath}`);
21
+
22
+ this._watcher = fs.watch(this._filePath, (eventType) => {
23
+ if (eventType !== 'change') return;
24
+
25
+ // Debounce rapid file system events
26
+ clearTimeout(this._debounceTimer);
27
+ this._debounceTimer = setTimeout(() => {
28
+ this._reload();
29
+ }, 300);
30
+ });
31
+ }
32
+
33
+ _reload() {
34
+ try {
35
+ const configFile = readers.text_reader(this._filePath);
36
+ const parsedConfiguration = YAML.parse(configFile());
37
+
38
+ if (parsedConfiguration.port === undefined) {
39
+ this._logger.error('Hot-reload skipped: port property is required');
40
+ return;
41
+ }
42
+
43
+ this._logger.message('');
44
+ this._logger.info('Configuration file changed. Reloading...');
45
+ this._onChange(parsedConfiguration);
46
+ } catch (error) {
47
+ this._logger.error(`Hot-reload failed: ${error.message}`);
48
+ }
49
+ }
50
+
51
+ stop() {
52
+ if (this._watcher) {
53
+ this._watcher.close();
54
+ this._watcher = null;
55
+ }
56
+ clearTimeout(this._debounceTimer);
57
+ }
58
+ }
59
+
60
+ module.exports = ConfigWatcher;
@@ -1,44 +1,44 @@
1
- const readers = require("./readers");
2
-
3
- const parseProperties = function (properties) {
4
- let property = {
5
- startIndex: 0,
6
- format: "json",
7
- direction: "rand"
8
- };
9
-
10
- if (properties === undefined) return property;
11
-
12
- const props = properties;
13
-
14
- if (props.length < 3) throw new Error("Invalid properties");
15
- if (isNaN(props[2])) throw new Error("Index must be a number");
16
-
17
- property.startIndex = parseFloat(props[2]);
18
- property.format = props[0];
19
- property.direction = props[1];
20
-
21
- return property;
22
- }
23
-
24
- const injectHandlers = function (data) {
25
-
26
- for (const variable in data) {
27
- if (Object.hasOwnProperty.call(data, variable)) {
28
- const node = data[variable];
29
-
30
- if (node.path === undefined) throw new Error("Node requires a path");
31
- if (node.reader === undefined) throw new Error("Node requires a reader");
32
- if (readers[node.reader + "_reader"] === undefined) throw new Error("Selected reader cannot be found");
33
-
34
- const properties = parseProperties(node.properties);
35
-
36
- const nodeHandler = readers[node.reader + "_reader"];
37
- node.dataHandler = nodeHandler(node.path, properties);
38
- }
39
- }
40
- };
41
-
42
- module.exports = {
43
- loadHandlersFromConfiguration: injectHandlers
1
+ const readers = require("./readers");
2
+
3
+ const parseProperties = function (properties) {
4
+ let property = {
5
+ startIndex: 0,
6
+ format: "json",
7
+ direction: "rand"
8
+ };
9
+
10
+ if (properties === undefined) return property;
11
+
12
+ const props = properties;
13
+
14
+ if (props.length < 3) throw new Error("Invalid properties");
15
+ if (isNaN(props[2])) throw new Error("Index must be a number");
16
+
17
+ property.startIndex = parseFloat(props[2]);
18
+ property.format = props[0];
19
+ property.direction = props[1];
20
+
21
+ return property;
22
+ }
23
+
24
+ const injectHandlers = function (data) {
25
+
26
+ for (const variable in data) {
27
+ if (Object.hasOwnProperty.call(data, variable)) {
28
+ const node = data[variable];
29
+
30
+ if (node.path === undefined) throw new Error("Node requires a path");
31
+ if (node.reader === undefined) throw new Error("Node requires a reader");
32
+ if (readers[node.reader + "_reader"] === undefined) throw new Error("Selected reader cannot be found");
33
+
34
+ const properties = parseProperties(node.properties);
35
+
36
+ const nodeHandler = readers[node.reader + "_reader"];
37
+ node.dataHandler = nodeHandler(node.path, properties);
38
+ }
39
+ }
40
+ };
41
+
42
+ module.exports = {
43
+ loadHandlersFromConfiguration: injectHandlers
44
44
  }
@@ -1,96 +1,96 @@
1
- module.exports = {
2
- BASE_URL: "http://localhost",
3
- CONFIG_FILE_NAME: ".mockapi-config",
4
- LOG_LEVELS: {
5
- DEBUG: "debug",
6
- ERROR: "error",
7
- VERBOSE: "verbose",
8
- NONE: "none"
9
- },
10
- EXTERNAL_MODULES_PATH: "apiHandlers/",
11
- DEFAULT_CONTENT_TYPE: "text/plain",
12
- HTTP_STATUS_CODES: {
13
- CONTINUE :100,
14
- SWITCHING_PROTOCOLS :101,
15
- PROCESSING :102,
16
- OK :200,
17
- CREATED :201,
18
- ACCEPTED :202,
19
- NON_AUTHORITATIVE_INFORMATION :203,
20
- NO_CONTENT :204,
21
- RESET_CONTENT :205,
22
- PARTIAL_CONTENT :206,
23
- MULTI_STATUS :207,
24
- MULTIPLE_CHOICES :300,
25
- MOVED_PERMANENTLY :301,
26
- MOVED_TEMPORARILY :302,
27
- SEE_OTHER :303,
28
- NOT_MODIFIED :304,
29
- USE_PROXY :305,
30
- TEMPORARY_REDIRECT :307,
31
- PERMANENT_REDIRECT :308,
32
- BAD_REQUEST :400,
33
- UNAUTHORIZED :401,
34
- PAYMENT_REQUIRED :402,
35
- FORBIDDEN :403,
36
- NOT_FOUND :404,
37
- METHOD_NOT_ALLOWED :405,
38
- NOT_ACCEPTABLE :406,
39
- PROXY_AUTHENTICATION_REQUIRED :407,
40
- REQUEST_TIMEOUT :408,
41
- CONFLICT :409,
42
- GONE :410,
43
- LENGTH_REQUIRED :411,
44
- PRECONDITION_FAILED :412,
45
- REQUEST_TOO_LONG :413,
46
- REQUEST_URI_TOO_LONG :414,
47
- UNSUPPORTED_MEDIA_TYPE :415,
48
- REQUESTED_RANGE_NOT_SATISFIABLE :416,
49
- EXPECTATION_FAILED :417,
50
- IM_A_TEAPOT :418,
51
- INSUFFICIENT_SPACE_ON_RESOURCE :419,
52
- METHOD_FAILURE :420,
53
- UNPROCESSABLE_ENTITY :422,
54
- LOCKED :423,
55
- FAILED_DEPENDENCY :424,
56
- PRECONDITION_REQUIRED :428,
57
- TOO_MANY_REQUESTS :429,
58
- REQUEST_HEADER_FIELDS_TOO_LARGE :431,
59
- UNAVAILABLE_FOR_LEGAL_REASONS :451,
60
- INTERNAL_SERVER_ERROR :500,
61
- NOT_IMPLEMENTED :501,
62
- BAD_GATEWAY :502,
63
- SERVICE_UNAVAILABLE :503,
64
- GATEWAY_TIMEOUT :504,
65
- HTTP_VERSION_NOT_SUPPORTED :505,
66
- INSUFFICIENT_STORAGE :507,
67
- NETWORK_AUTHENTICATION_REQUIRED :511
68
- },
69
- COLOR: {
70
- reset: '\x1b[0m',
71
- bright: '\x1b[1m',
72
- dim: '\x1b[2m',
73
- underscore: '\x1b[4m',
74
- blink: '\x1b[5m',
75
- reverse: '\x1b[7m',
76
- hidden: '\x1b[8m',
77
-
78
- fgBlack: '\x1b[30m',
79
- fgRed: '\x1b[31m',
80
- fgGreen: '\x1b[32m',
81
- fgYellow: '\x1b[33m',
82
- fgBlue: '\x1b[34m',
83
- fgMagenta: '\x1b[35m',
84
- fgCyan: '\x1b[36m',
85
- fgWhite: '\x1b[37m',
86
-
87
- bgBlack: '\x1b[40m',
88
- bgRed: '\x1b[41m',
89
- bgGreen: '\x1b[42m',
90
- bgYellow: '\x1b[43m',
91
- bgBlue: '\x1b[44m',
92
- bgMagenta: '\x1b[45m',
93
- bgCyan: '\x1b[46m',
94
- bgWhite: '\x1b[47m'
95
- }
1
+ module.exports = {
2
+ BASE_URL: "http://localhost",
3
+ CONFIG_FILE_NAME: ".mockapi-config",
4
+ LOG_LEVELS: {
5
+ DEBUG: "debug",
6
+ ERROR: "error",
7
+ VERBOSE: "verbose",
8
+ NONE: "none"
9
+ },
10
+ EXTERNAL_MODULES_PATH: "apiHandlers/",
11
+ DEFAULT_CONTENT_TYPE: "text/plain",
12
+ HTTP_STATUS_CODES: {
13
+ CONTINUE :100,
14
+ SWITCHING_PROTOCOLS :101,
15
+ PROCESSING :102,
16
+ OK :200,
17
+ CREATED :201,
18
+ ACCEPTED :202,
19
+ NON_AUTHORITATIVE_INFORMATION :203,
20
+ NO_CONTENT :204,
21
+ RESET_CONTENT :205,
22
+ PARTIAL_CONTENT :206,
23
+ MULTI_STATUS :207,
24
+ MULTIPLE_CHOICES :300,
25
+ MOVED_PERMANENTLY :301,
26
+ MOVED_TEMPORARILY :302,
27
+ SEE_OTHER :303,
28
+ NOT_MODIFIED :304,
29
+ USE_PROXY :305,
30
+ TEMPORARY_REDIRECT :307,
31
+ PERMANENT_REDIRECT :308,
32
+ BAD_REQUEST :400,
33
+ UNAUTHORIZED :401,
34
+ PAYMENT_REQUIRED :402,
35
+ FORBIDDEN :403,
36
+ NOT_FOUND :404,
37
+ METHOD_NOT_ALLOWED :405,
38
+ NOT_ACCEPTABLE :406,
39
+ PROXY_AUTHENTICATION_REQUIRED :407,
40
+ REQUEST_TIMEOUT :408,
41
+ CONFLICT :409,
42
+ GONE :410,
43
+ LENGTH_REQUIRED :411,
44
+ PRECONDITION_FAILED :412,
45
+ REQUEST_TOO_LONG :413,
46
+ REQUEST_URI_TOO_LONG :414,
47
+ UNSUPPORTED_MEDIA_TYPE :415,
48
+ REQUESTED_RANGE_NOT_SATISFIABLE :416,
49
+ EXPECTATION_FAILED :417,
50
+ IM_A_TEAPOT :418,
51
+ INSUFFICIENT_SPACE_ON_RESOURCE :419,
52
+ METHOD_FAILURE :420,
53
+ UNPROCESSABLE_ENTITY :422,
54
+ LOCKED :423,
55
+ FAILED_DEPENDENCY :424,
56
+ PRECONDITION_REQUIRED :428,
57
+ TOO_MANY_REQUESTS :429,
58
+ REQUEST_HEADER_FIELDS_TOO_LARGE :431,
59
+ UNAVAILABLE_FOR_LEGAL_REASONS :451,
60
+ INTERNAL_SERVER_ERROR :500,
61
+ NOT_IMPLEMENTED :501,
62
+ BAD_GATEWAY :502,
63
+ SERVICE_UNAVAILABLE :503,
64
+ GATEWAY_TIMEOUT :504,
65
+ HTTP_VERSION_NOT_SUPPORTED :505,
66
+ INSUFFICIENT_STORAGE :507,
67
+ NETWORK_AUTHENTICATION_REQUIRED :511
68
+ },
69
+ COLOR: {
70
+ reset: '\x1b[0m',
71
+ bright: '\x1b[1m',
72
+ dim: '\x1b[2m',
73
+ underscore: '\x1b[4m',
74
+ blink: '\x1b[5m',
75
+ reverse: '\x1b[7m',
76
+ hidden: '\x1b[8m',
77
+
78
+ fgBlack: '\x1b[30m',
79
+ fgRed: '\x1b[31m',
80
+ fgGreen: '\x1b[32m',
81
+ fgYellow: '\x1b[33m',
82
+ fgBlue: '\x1b[34m',
83
+ fgMagenta: '\x1b[35m',
84
+ fgCyan: '\x1b[36m',
85
+ fgWhite: '\x1b[37m',
86
+
87
+ bgBlack: '\x1b[40m',
88
+ bgRed: '\x1b[41m',
89
+ bgGreen: '\x1b[42m',
90
+ bgYellow: '\x1b[43m',
91
+ bgBlue: '\x1b[44m',
92
+ bgMagenta: '\x1b[45m',
93
+ bgCyan: '\x1b[46m',
94
+ bgWhite: '\x1b[47m'
95
+ }
96
96
  };