mockaton 9.4.2 → 9.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "HTTP Mock Server",
4
4
  "type": "module",
5
- "version": "9.4.2",
5
+ "version": "9.5.1",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
package/src/Dashboard.css CHANGED
@@ -102,18 +102,12 @@ select, a, input, button {
102
102
 
103
103
  a {
104
104
  text-decoration: none;
105
-
105
+
106
106
  &:hover {
107
107
  text-decoration: underline;
108
108
  }
109
109
  }
110
110
 
111
- input[type="checkbox"] {
112
- &:focus {
113
- outline: 0;
114
- }
115
- }
116
-
117
111
  a,
118
112
  button,
119
113
  input[type=checkbox],
@@ -161,7 +155,7 @@ header {
161
155
  display: flex;
162
156
  flex-wrap: wrap;
163
157
  align-items: flex-end;
164
- gap: 16px 8px;
158
+ gap: 16px 10px;
165
159
 
166
160
  @media (max-width: 800px) {
167
161
  max-width: 400px;
@@ -202,8 +196,7 @@ header {
202
196
  height: 28px;
203
197
  padding: 4px 8px;
204
198
  border: 1px solid var(--colorSecondaryActionBorder);
205
- border-right: 3px solid transparent;
206
- margin-top: 4px;
199
+ margin-top: 2px;
207
200
  color: var(--colorText);
208
201
  font-size: 11px;
209
202
  background-color: var(--colorComboBoxHeaderBackground);
@@ -211,6 +204,7 @@ header {
211
204
  }
212
205
 
213
206
  select:enabled:hover {
207
+ border-color: var(--colorSecondaryActionBorder);
214
208
  background: var(--colorHover);
215
209
  }
216
210
 
@@ -218,7 +212,7 @@ header {
218
212
  width: 84px;
219
213
 
220
214
  input[type=number] {
221
- padding-right: 0;
215
+ padding-right: 4px;
222
216
  }
223
217
 
224
218
  svg {
@@ -230,6 +224,10 @@ header {
230
224
  }
231
225
  }
232
226
 
227
+ &.CookieSelector {
228
+ width: 100px;
229
+ }
230
+
233
231
  &.FallbackBackend {
234
232
  position: relative;
235
233
  width: 160px;
@@ -272,11 +270,14 @@ header {
272
270
  }
273
271
 
274
272
  .MenuTrigger {
275
- min-width: 24px;
273
+ width: 24px;
274
+ height: 24px;
275
+ flex-shrink: 0;
276
276
  align-self: end;
277
277
  margin-left: auto;
278
278
  fill: var(--colorSecondaryAction);
279
279
  background: transparent;
280
+ border-radius: 50%;
280
281
 
281
282
  &:hover {
282
283
  fill: var(--colorAccent);
@@ -295,7 +296,7 @@ header {
295
296
  border-radius: var(--radius);
296
297
  box-shadow: var(--boxShadow1);
297
298
  background: var(--colorHeaderBackground);
298
-
299
+
299
300
  a {
300
301
  color: var(--colorAccent);
301
302
  }
@@ -438,7 +439,7 @@ table {
438
439
  > input {
439
440
  appearance: none;
440
441
 
441
- &:focus-visible {
442
+ &:focus {
442
443
  outline: 0;
443
444
  & ~ svg {
444
445
  outline: 2px solid var(--colorAccent)
@@ -530,7 +531,7 @@ table {
530
531
  .InternalServerErrorToggler,
531
532
  .NotFoundToggler {
532
533
  display: flex;
533
- margin-right: 12px;
534
+ margin-right: 10px;
534
535
  margin-left: 8px;
535
536
  cursor: pointer;
536
537
 
package/src/Dashboard.js CHANGED
@@ -33,6 +33,7 @@ const Strings = {
33
33
 
34
34
  const CSS = {
35
35
  BulkSelector: null,
36
+ CookieSelector: null,
36
37
  DelayToggler: null,
37
38
  ErrorToast: null,
38
39
  FallbackBackend: null,
@@ -195,7 +196,7 @@ function CookieSelector() {
195
196
  }
196
197
  const disabled = cookies.length <= 1
197
198
  return (
198
- r('label', className(CSS.Field),
199
+ r('label', className(CSS.Field, CSS.CookieSelector),
199
200
  r('span', null, Strings.cookie),
200
201
  r('select', {
201
202
  autocomplete: 'off',
@@ -2,7 +2,7 @@ import { join } from 'node:path'
2
2
  import { readFileSync } from 'node:fs'
3
3
  import { pathToFileURL } from 'node:url'
4
4
 
5
- import { log } from './utils/log.js'
5
+ import { logger } from './utils/logger.js'
6
6
  import { proxy } from './ProxyRelay.js'
7
7
  import { cookie } from './cookie.js'
8
8
  import { mimeFor } from './utils/mime.js'
@@ -25,7 +25,7 @@ export async function dispatchMock(req, response) {
25
25
  return
26
26
  }
27
27
 
28
- log.access(req.url, broker.file)
28
+ logger.accessMock(req.url, broker.file)
29
29
  response.statusCode = broker.status
30
30
 
31
31
  if (cookie.getCurrent())
@@ -46,11 +46,6 @@ export async function dispatchMock(req, response) {
46
46
  catch (error) {
47
47
  if (error?.code === 'ENOENT') // mock-file has been deleted
48
48
  sendNotFound(response)
49
- else if (error?.code === 'ERR_UNKNOWN_FILE_EXTENSION') {
50
- if (error.toString().includes('Unknown file extension ".ts'))
51
- log.warn('\nLooks like you need a TypeScript compiler\n')
52
- sendInternalServerError(response, error)
53
- }
54
49
  else
55
50
  sendInternalServerError(response, error)
56
51
  }
package/src/Mockaton.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createServer } from 'node:http'
2
2
 
3
- import { log } from './utils/log.js'
3
+ import { logger } from './utils/logger.js'
4
4
  import { API } from './ApiConstants.js'
5
5
  import { config, setup } from './config.js'
6
6
  import { dispatchMock } from './MockDispatcher.js'
@@ -27,8 +27,8 @@ export function Mockaton(options) {
27
27
  server.listen(config.port, config.host, function () {
28
28
  const { address, port } = this.address()
29
29
  const url = `http://${address}:${port}`
30
- log.info('Listening', url)
31
- log.info('Dashboard', url + API.dashboard)
30
+ logger.info('Listening', url)
31
+ logger.info('Dashboard', url + API.dashboard)
32
32
  config.onReady(url + API.dashboard)
33
33
  })
34
34
 
@@ -37,7 +37,7 @@ export function Mockaton(options) {
37
37
 
38
38
 
39
39
  async function onRequest(req, response) {
40
- response.on('error', log.warn)
40
+ response.on('error', logger.warn)
41
41
 
42
42
  try {
43
43
  response.setHeader('Server', 'Mockaton')
@@ -1,7 +1,7 @@
1
1
  import { join } from 'node:path'
2
2
  import { readFileSync } from 'node:fs'
3
3
 
4
- import { log } from './utils/log.js'
4
+ import { logger } from './utils/logger.js'
5
5
  import { mimeFor } from './utils/mime.js'
6
6
  import { brokerByRoute } from './staticCollection.js'
7
7
  import { config, calcDelay } from './config.js'
@@ -13,12 +13,12 @@ export async function dispatchStatic(req, response) {
13
13
 
14
14
  setTimeout(async () => {
15
15
  if (!broker || broker.status === 404) { // TESTME
16
- log.access(req.url, 'static404')
16
+ logger.accessMock(req.url, 'static404')
17
17
  sendNotFound(response)
18
18
  return
19
19
  }
20
20
 
21
- log.access(req.url, 'static200')
21
+ logger.accessMock(req.url, 'static200')
22
22
 
23
23
  const file = join(config.staticDir, broker.route)
24
24
  if (req.headers.range)
package/src/config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { join, isAbsolute } from 'node:path'
2
2
 
3
- import { log } from './utils/log.js'
3
+ import { logger } from './utils/logger.js'
4
4
  import { isDirectory } from './utils/fs.js'
5
5
  import { openInBrowser } from './utils/openInBrowser.js'
6
6
  import { jsToJsonPlugin } from './MockDispatcher.js'
@@ -23,7 +23,7 @@ const schema = {
23
23
  host: ['127.0.0.1', is(String)],
24
24
  port: [0, port => Number.isInteger(port) && port >= 0 && port < 2 ** 16], // 0 means auto-assigned
25
25
 
26
- logLevel: ['normal', val => ['normal', 'quiet'].includes(val)],
26
+ logLevel: ['normal', val => ['normal', 'quiet', 'verbose'].includes(val)],
27
27
 
28
28
  delay: [1200, ms => Number.isInteger(ms) && ms >= 0],
29
29
  delayJitter: [0, percent => percent >= 0 && percent <= 3],
@@ -80,7 +80,7 @@ export function setup(options) {
80
80
 
81
81
  Object.assign(config, options)
82
82
  validate(config, ConfigValidator)
83
- log.setLevel(config.logLevel)
83
+ logger.setLevel(config.logLevel)
84
84
  }
85
85
 
86
86
 
@@ -1,6 +1,6 @@
1
1
  import { basename } from 'node:path'
2
2
 
3
- import { log } from './utils/log.js'
3
+ import { logger } from './utils/logger.js'
4
4
  import { cookie } from './cookie.js'
5
5
  import { MockBroker } from './MockBroker.js'
6
6
  import { listFilesRecursively } from './utils/fs.js'
@@ -68,7 +68,7 @@ export function registerMock(file, isFromWatcher = false) {
68
68
  function filenameIsValid(file) {
69
69
  const error = validateFilename(file)
70
70
  if (error)
71
- log.warn(error, file)
71
+ logger.warn(error, file)
72
72
  return !error
73
73
  }
74
74
 
package/src/utils/fs.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { join, dirname, sep, posix } from 'node:path'
2
2
  import { lstatSync, readdirSync, writeFileSync, mkdirSync } from 'node:fs'
3
- import { log } from './log.js'
3
+ import { logger } from './logger.js'
4
4
 
5
5
 
6
6
  export const isFile = path => lstatSync(path, { throwIfNoEntry: false })?.isFile()
@@ -25,6 +25,6 @@ export const write = (path, body) => {
25
25
  writeFileSync(path, body)
26
26
  }
27
27
  catch (err) {
28
- log.warn('Write access denied', err)
28
+ logger.warn('Write access denied', err)
29
29
  }
30
30
  }
@@ -1,47 +1,54 @@
1
1
  import fs, { readFileSync } from 'node:fs'
2
- import { log } from './log.js'
2
+ import { logger } from './logger.js'
3
3
  import { mimeFor } from './mime.js'
4
4
  import { HEADER_FOR_502 } from '../ApiConstants.js'
5
5
 
6
6
 
7
7
  export function sendOK(response) {
8
- response.end()
9
- }
10
-
11
- export function sendNoContent(response) {
12
- response.statusCode = 204
8
+ logger.access(response)
13
9
  response.end()
14
10
  }
15
11
 
16
12
  export function sendJSON(response, payload) {
13
+ logger.access(response)
17
14
  response.setHeader('Content-Type', 'application/json')
18
15
  response.end(JSON.stringify(payload))
19
16
  }
20
17
 
21
18
  export function sendFile(response, file) {
19
+ logger.access(response)
22
20
  response.setHeader('Content-Type', mimeFor(file))
23
21
  response.end(readFileSync(file, 'utf8'))
24
22
  }
25
23
 
24
+ export function sendNoContent(response) {
25
+ response.statusCode = 204
26
+ logger.access(response)
27
+ response.end()
28
+ }
29
+
30
+
26
31
  export function sendNotFound(response) {
27
32
  response.statusCode = 404
33
+ logger.access(response)
28
34
  response.end()
29
35
  }
30
36
 
31
37
  export function sendUnprocessableContent(response, error) {
32
- log.warn(error)
38
+ logger.warn(error)
33
39
  response.statusCode = 422
34
40
  response.end(error)
35
41
  }
36
42
 
43
+
37
44
  export function sendInternalServerError(response, error) {
38
- log.error(error?.message || error, error?.stack || undefined)
45
+ logger.error(error?.message || error, error?.stack || undefined)
39
46
  response.statusCode = 500
40
47
  response.end()
41
48
  }
42
49
 
43
50
  export function sendBadGateway(response, error) {
44
- log.warn('Fallback Proxy Error:', error.cause.message)
51
+ logger.warn('Fallback Proxy Error:', error.cause.message)
45
52
  response.statusCode = 502
46
53
  response.setHeader(HEADER_FOR_502, 1)
47
54
  response.end()
@@ -0,0 +1,42 @@
1
+ export const logger = new class {
2
+ #level = 'normal'
3
+
4
+ setLevel(level) {
5
+ this.#level = level
6
+ }
7
+
8
+ info(...msg) {
9
+ if (this.#level !== 'quiet')
10
+ console.info(this.#msg('INFO', ...msg))
11
+ }
12
+
13
+ accessMock(url, ...msg) {
14
+ if (this.#level !== 'quiet')
15
+ console.log(this.#msg('MOCK', this.#sanitizeURL(url), ...msg))
16
+ }
17
+
18
+ access(response) {
19
+ if (this.#level === 'verbose')
20
+ console.log(this.#msg(
21
+ 'ACCESS',
22
+ response.req.method,
23
+ response.statusCode,
24
+ this.#sanitizeURL(response.req.url)))
25
+ }
26
+
27
+ warn(...msg) {
28
+ console.warn(this.#msg('WARN', ...msg))
29
+ }
30
+
31
+ error(...msg) {
32
+ console.error(this.#msg('ERROR', ...msg))
33
+ }
34
+
35
+ #msg(...msg) {
36
+ return [new Date().toISOString(), ...msg].join('::')
37
+ }
38
+
39
+ #sanitizeURL(url) {
40
+ return decodeURIComponent(url).replace(/[\x00-\x1F\x7F\x9B]/g, '')
41
+ }
42
+ }
package/src/utils/log.js DELETED
@@ -1,34 +0,0 @@
1
- export const log = new class {
2
- #level = 'normal'
3
-
4
- setLevel(level) {
5
- this.#level = level
6
- }
7
-
8
- info(...msg) {
9
- if (this.#level !== 'quiet')
10
- console.info([this.#date, 'INFO', ...msg].join('::'))
11
- }
12
-
13
- access(url, ...msg) {
14
- if (this.#level !== 'quiet')
15
- console.log([this.#date, 'ACCESS', this.#sanitizeURL(url), ...msg].join('::'))
16
- }
17
-
18
- warn(...msg) {
19
- console.warn([this.#date, 'WARN', ...msg].join('::'))
20
- }
21
-
22
- error(...msg) {
23
- console.error([this.#date, 'ERROR', ...msg].join('::'))
24
- }
25
-
26
-
27
- get #date() {
28
- return new Date().toISOString()
29
- }
30
-
31
- #sanitizeURL(url) {
32
- return decodeURIComponent(url).replace(/[\x00-\x1F\x7F\x9B]/g, '')
33
- }
34
- }