mockaton 8.16.1 → 8.16.2

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": "8.16.1",
5
+ "version": "8.16.2",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
package/src/Api.js CHANGED
@@ -25,7 +25,9 @@ const dashboardAssets = [
25
25
 
26
26
  export const apiGetRequests = new Map([
27
27
  [API.dashboard, serveDashboard],
28
- ...dashboardAssets.map(f => [API.dashboard + f, serveDashboardAsset(f)]),
28
+ ...dashboardAssets.map(f => [
29
+ API.dashboard + f, serveDashboardAsset(f)
30
+ ]),
29
31
  [API.cors, getIsCorsAllowed],
30
32
  [API.static, listStaticFiles],
31
33
  [API.mocks, listMockBrokers],
@@ -49,7 +51,7 @@ export const apiPatchRequests = new Map([
49
51
  [API.globalDelay, setGlobalDelay],
50
52
  [API.collectProxied, setCollectProxied],
51
53
  [API.delayStatic, setStaticRouteIsDelayed],
52
- [API.notFoundStatic, setStaticRouteIsNotFound]
54
+ [API.staticStatus, setStaticRouteStatusCode]
53
55
  ])
54
56
 
55
57
 
@@ -66,7 +68,7 @@ function serveDashboardAsset(f) {
66
68
 
67
69
  function listCookies(_, response) { sendJSON(response, cookie.list()) }
68
70
  function listComments(_, response) { sendJSON(response, mockBrokersCollection.extractAllComments()) }
69
- function listStaticFiles(req, response) { sendJSON(response, getStaticFilesCollection()) }
71
+ function listStaticFiles(_, response) { sendJSON(response, getStaticFilesCollection()) }
70
72
  function getGlobalDelay(_, response) { sendJSON(response, config.delay) }
71
73
  function listMockBrokers(_, response) { sendJSON(response, mockBrokersCollection.getAll()) }
72
74
  function getProxyFallback(_, response) { sendJSON(response, config.proxyFallback) }
@@ -86,12 +88,10 @@ function longPollClientSyncVersion(req, response) {
86
88
  }
87
89
 
88
90
  response.setTimeout(LONG_POLL_SERVER_TIMEOUT, onAddOrRemoveMock)
89
-
90
91
  req.on('error', () => {
91
92
  uiSyncVersion.unsubscribe(onAddOrRemoveMock)
92
93
  response.destroy()
93
94
  })
94
-
95
95
  uiSyncVersion.subscribe(onAddOrRemoveMock)
96
96
  }
97
97
 
@@ -136,7 +136,7 @@ async function setRouteIsDelayed(req, response) {
136
136
  else if (typeof delayed !== 'boolean')
137
137
  sendUnprocessableContent(response, `Expected a boolean for "delayed"`) // TESTME
138
138
  else {
139
- broker.updateDelayed(body[DF.delayed])
139
+ broker.setDelayed(delayed)
140
140
  sendOK(response)
141
141
  }
142
142
  }
@@ -155,7 +155,7 @@ async function setRouteIsProxied(req, response) { // TESTME
155
155
  else if (proxied && !config.proxyFallback)
156
156
  sendUnprocessableContent(response, `There’s no proxy fallback`)
157
157
  else {
158
- broker.updateProxied(proxied)
158
+ broker.setProxied(proxied)
159
159
  sendOK(response)
160
160
  }
161
161
  }
@@ -198,17 +198,17 @@ async function setGlobalDelay(req, response) { // TESTME
198
198
  }
199
199
 
200
200
 
201
- async function setStaticRouteIsNotFound(req, response) {
201
+ async function setStaticRouteStatusCode(req, response) {
202
202
  const body = await parseJSON(req)
203
- const shouldBeNotFound = body[DF.shouldBeNotFound]
203
+ const status = Number(body[DF.statusCode])
204
204
  const broker = findStaticBrokerByRoute(body[DF.routeUrlMask])
205
205
 
206
206
  if (!broker) // TESTME
207
207
  sendUnprocessableContent(response, `Route does not exist: ${body[DF.routeUrlMask]}`)
208
- else if (typeof shouldBeNotFound !== 'boolean')
209
- sendUnprocessableContent(response, `Expected a boolean for "not found"`) // TESTME
208
+ else if (!(status === 200 || status === 404))
209
+ sendUnprocessableContent(response, `Expected a 200 or 404 status code. Received ${status}`) // TESTME
210
210
  else {
211
- broker.updateNotFound(body[DF.shouldBeNotFound])
211
+ broker.setStatus(status)
212
212
  sendOK(response)
213
213
  }
214
214
  }
@@ -216,15 +216,15 @@ async function setStaticRouteIsNotFound(req, response) {
216
216
 
217
217
  async function setStaticRouteIsDelayed(req, response) {
218
218
  const body = await parseJSON(req)
219
- const shouldBeNotFound = body[DF.delayed]
219
+ const delayed = body[DF.delayed]
220
220
  const broker = findStaticBrokerByRoute(body[DF.routeUrlMask])
221
221
 
222
222
  if (!broker) // TESTME
223
223
  sendUnprocessableContent(response, `Route does not exist: ${body[DF.routeUrlMask]}`)
224
- else if (typeof shouldBeNotFound !== 'boolean')
225
- sendUnprocessableContent(response, `Expected a boolean for "delayed"`) // TESTME
224
+ else if (typeof delayed !== 'boolean')
225
+ sendUnprocessableContent(response, `Expected a boolean for "delayed". Received ${delayed}`) // TESTME
226
226
  else {
227
- broker.updateDelayed(body[DF.delayed])
227
+ broker.setDelayed(delayed)
228
228
  sendOK(response)
229
229
  }
230
230
  }
@@ -11,11 +11,11 @@ export const API = {
11
11
  fallback: MOUNT + '/fallback',
12
12
  globalDelay: MOUNT + '/global-delay',
13
13
  mocks: MOUNT + '/mocks',
14
- notFoundStatic: MOUNT + '/not-found-static',
15
14
  proxied: MOUNT + '/proxied',
16
15
  reset: MOUNT + '/reset',
17
16
  select: MOUNT + '/select',
18
17
  static: MOUNT + '/static',
18
+ staticStatus: MOUNT + '/static-status',
19
19
  syncVersion: MOUNT + '/sync_version'
20
20
  }
21
21
 
@@ -24,7 +24,7 @@ export const DF = { // Dashboard Fields (XHR)
24
24
  routeUrlMask: 'route_url_mask',
25
25
  delayed: 'delayed',
26
26
  proxied: 'proxied',
27
- shouldBeNotFound: 'should_be_not_found',
27
+ statusCode: 'status_code',
28
28
  syncVersion: 'last_received_sync_version'
29
29
  }
30
30
 
package/src/Commander.js CHANGED
@@ -44,10 +44,10 @@ export class Commander {
44
44
  })
45
45
  }
46
46
 
47
- setStaticRouteIs404(routeUrlMask, shouldBeNotFound) {
48
- return this.#patch(API.notFoundStatic, {
47
+ setStaticRouteStatus(routeUrlMask, status) {
48
+ return this.#patch(API.staticStatus, {
49
49
  [DF.routeUrlMask]: routeUrlMask,
50
- [DF.shouldBeNotFound]: shouldBeNotFound
50
+ [DF.statusCode]: status
51
51
  })
52
52
  }
53
53
 
package/src/Dashboard.js CHANGED
@@ -66,12 +66,10 @@ const CSS = {
66
66
 
67
67
  const r = createElement
68
68
  const s = createSvgElement
69
- const mockaton = new Commander(window.location.origin)
70
69
 
71
- const SPINNER_DELAY = 180
70
+ const mockaton = new Commander(window.location.origin)
72
71
  let globalDelay = 1200
73
72
 
74
-
75
73
  init()
76
74
  initLongPoll()
77
75
 
@@ -89,7 +87,7 @@ function init() {
89
87
  .catch(onError)
90
88
  }
91
89
 
92
- function App([brokersByMethod, cookies, comments, delay, collectProxied, fallbackAddress, staticFiles]) {
90
+ function App([brokersByMethod, cookies, comments, delay, collectProxied, fallbackAddress, staticBrokers]) {
93
91
  globalDelay = delay
94
92
  return (
95
93
  r('div', null,
@@ -97,7 +95,7 @@ function App([brokersByMethod, cookies, comments, delay, collectProxied, fallbac
97
95
  r('main', { className: CSS.Main },
98
96
  r('div', null,
99
97
  r(MockList, { brokersByMethod, canProxy: Boolean(fallbackAddress) }),
100
- r(StaticFilesList, { staticFiles })),
98
+ r(StaticFilesList, { brokers: staticBrokers })),
101
99
  r(PayloadViewer))))
102
100
  }
103
101
 
@@ -302,6 +300,7 @@ function PreviewLink({ method, urlMask, urlMaskDittoed }) {
302
300
  : tail))
303
301
  }
304
302
 
303
+ /** @param {{ broker: MockBroker }} props */
305
304
  function MockSelector({ broker }) {
306
305
  function onChange() {
307
306
  const { urlMask, method } = parseFilename(this.value)
@@ -338,6 +337,7 @@ function MockSelector({ broker }) {
338
337
  }, file))))
339
338
  }
340
339
 
340
+ /** @param {{ broker: MockBroker }} props */
341
341
  function DelayRouteToggler({ broker }) {
342
342
  function onChange() {
343
343
  const { method, urlMask } = parseFilename(broker.mocks[0])
@@ -356,6 +356,7 @@ function DelayRouteToggler({ broker }) {
356
356
  TimerIcon()))
357
357
  }
358
358
 
359
+ /** @param {{ broker: MockBroker }} props */
359
360
  function InternalServerErrorToggler({ broker }) {
360
361
  function onChange() {
361
362
  const { urlMask, method } = parseFilename(broker.mocks[0])
@@ -381,6 +382,7 @@ function InternalServerErrorToggler({ broker }) {
381
382
  r('span', null, '500')))
382
383
  }
383
384
 
385
+ /** @param {{ broker: MockBroker, disabled: boolean }} props */
384
386
  function ProxyToggler({ broker, disabled }) {
385
387
  function onChange() {
386
388
  const { urlMask, method } = parseFilename(broker.mocks[0])
@@ -404,32 +406,34 @@ function ProxyToggler({ broker, disabled }) {
404
406
  }
405
407
 
406
408
 
407
-
408
- /** # StaticFilesList */
409
-
410
- function StaticFilesList({ staticFiles }) {
411
- if (!Object.keys(staticFiles).length)
409
+ /**
410
+ * # StaticFilesList
411
+ * @param {{ brokers: StaticBroker[] }} props
412
+ */
413
+ function StaticFilesList({ brokers }) {
414
+ if (!Object.keys(brokers).length)
412
415
  return null
413
- const paths = dittoSplitPaths(Object.keys(staticFiles)).map(([ditto, tail]) => ditto
416
+ const dp = dittoSplitPaths(Object.keys(brokers)).map(([ditto, tail]) => ditto
414
417
  ? [r('span', null, ditto), tail]
415
418
  : tail)
416
419
  return (
417
420
  r('table', { className: CSS.StaticFilesList },
418
421
  r('tbody', null,
419
422
  r('th', { colspan: 4 }, Strings.static_get),
420
- Object.values(staticFiles).map((broker, i) =>
423
+ Object.values(brokers).map((broker, i) =>
421
424
  r('tr', null,
422
425
  r('td', null, r(ProxyStaticToggler, {})),
423
426
  r('td', null, r(DelayStaticRouteToggler, { broker })),
424
427
  r('td', null, r(NotFoundToggler, { broker })),
425
- r('td', null, r('a', { href: broker.file, target: '_blank' }, paths[i]))
428
+ r('td', null, r('a', { href: broker.route, target: '_blank' }, dp[i]))
426
429
  )))))
427
430
  }
428
431
 
429
432
 
433
+ /** @param {{ broker: StaticBroker }} props */
430
434
  function DelayStaticRouteToggler({ broker }) {
431
435
  function onChange() {
432
- mockaton.setStaticRouteIsDelayed(broker.file, this.checked)
436
+ mockaton.setStaticRouteIsDelayed(broker.route, this.checked)
433
437
  .catch(onError)
434
438
  }
435
439
  return (
@@ -445,9 +449,10 @@ function DelayStaticRouteToggler({ broker }) {
445
449
  TimerIcon()))
446
450
  }
447
451
 
452
+ /** @param {{ broker: StaticBroker }} props */
448
453
  function NotFoundToggler({ broker }) {
449
454
  function onChange() {
450
- mockaton.setStaticRouteIs404(broker.file, this.checked)
455
+ mockaton.setStaticRouteStatus(broker.route, this.checked ? 404 : 200)
451
456
  .catch(onError)
452
457
  }
453
458
  return (
@@ -457,15 +462,13 @@ function NotFoundToggler({ broker }) {
457
462
  },
458
463
  r('input', {
459
464
  type: 'checkbox',
460
- checked: broker.should404,
465
+ checked: broker.status === 404,
461
466
  onChange
462
467
  }),
463
468
  r('span', null, '404')))
464
469
  }
465
470
 
466
-
467
- // TODO
468
- function ProxyStaticToggler({}) {
471
+ function ProxyStaticToggler({}) { // TODO
469
472
  function onChange() {
470
473
  }
471
474
  return (
@@ -523,7 +526,7 @@ function PayloadViewerTitleWhenProxied({ mime, status, statusText, gatewayIsBad
523
526
  }
524
527
 
525
528
  async function previewMock(method, urlMask, href) {
526
- const timer = setTimeout(renderSpinner, SPINNER_DELAY)
529
+ const timer = setTimeout(renderSpinner, 180)
527
530
  const response = await fetch(href, { method })
528
531
  clearTimeout(timer)
529
532
  await updatePayloadViewer(method, urlMask, response)
package/src/MockBroker.js CHANGED
@@ -83,11 +83,11 @@ export class MockBroker {
83
83
  this.currentMock.file = filename
84
84
  }
85
85
 
86
- updateDelayed(delayed) {
86
+ setDelayed(delayed) {
87
87
  this.currentMock.delayed = delayed
88
88
  }
89
89
 
90
- updateProxied(proxied) {
90
+ setProxied(proxied) {
91
91
  if (proxied)
92
92
  this.selectFile('')
93
93
  else
package/src/Mockaton.js CHANGED
@@ -54,7 +54,7 @@ async function onRequest(req, response) {
54
54
  else if (method === 'GET' && apiGetRequests.has(url))
55
55
  apiGetRequests.get(url)(req, response)
56
56
 
57
- else if (method === 'GET' && findStaticBrokerByRoute(req.url))
57
+ else if (method === 'GET' && findStaticBrokerByRoute(url))
58
58
  await dispatchStatic(req, response)
59
59
 
60
60
  else
@@ -1,37 +1,24 @@
1
- import { join, basename } from 'node:path'
2
1
  import { readFileSync } from 'node:fs'
2
+ import { join, basename } from 'node:path'
3
3
 
4
4
  import { mimeFor } from './utils/mime.js'
5
+ import { listFilesRecursively } from './utils/fs.js'
5
6
  import { config, isFileAllowed, calcDelay } from './config.js'
6
7
  import { sendPartialContent, sendNotFound } from './utils/http-response.js'
7
- import { isDirectory, isFile, listFilesRecursively } from './utils/fs.js'
8
8
 
9
9
 
10
10
  class StaticBroker {
11
- constructor(file) {
12
- this.file = file
11
+ constructor(route) {
12
+ this.route = route
13
13
  this.delayed = false
14
- this.should404 = false
15
- this.resolvedPath = this.#staticFilePath()
16
- }
17
-
18
- #staticFilePath() { // url is absolute e.g. /home/../.. => /
19
- let candidate = join(config.staticDir, this.file)
20
- if (isDirectory(candidate))
21
- candidate = join(candidate, 'index.html')
22
- if (isFile(candidate))
23
- return candidate
24
- }
25
-
26
- updateDelayed(value) {
27
- this.delayed = value
14
+ this.status = 200 // 200 or 404
28
15
  }
29
16
 
30
- updateNotFound(value) {
31
- this.should404 = value
32
- }
17
+ setDelayed(value) { this.delayed = value }
18
+ setStatus(value) { this.status = value }
33
19
  }
34
20
 
21
+ /** @type {{ [route: string]: StaticBroker }} */
35
22
  let collection = {}
36
23
 
37
24
  export function initStaticCollection() {
@@ -41,23 +28,27 @@ export function initStaticCollection() {
41
28
  .forEach(registerStaticMock)
42
29
  }
43
30
 
31
+
44
32
  /** @returns {boolean} registered */
45
- export function registerStaticMock(file) {
46
- if (!isFileAllowed(basename(file)))
33
+ export function registerStaticMock(relativeFile) {
34
+ if (!isFileAllowed(basename(relativeFile)))
47
35
  return false
48
36
 
49
- file = '/' + file
50
- if (findStaticBrokerByRoute(file))
37
+ const route = '/' + relativeFile
38
+ if (findStaticBrokerByRoute(route))
51
39
  return false
52
40
 
53
- collection[file] = new StaticBroker(file)
41
+ collection[route] = new StaticBroker(route)
54
42
  return true
55
43
  }
56
44
 
57
- export function unregisterStaticMock(file) {
58
- delete collection['/' + file]
45
+
46
+ export function unregisterStaticMock(relativeFile) {
47
+ delete collection['/' + relativeFile]
59
48
  }
60
49
 
50
+
51
+ /** @returns {StaticBroker | undefined} */
61
52
  export function findStaticBrokerByRoute(route) {
62
53
  return collection[route] || collection[join(route, 'index.html')]
63
54
  }
@@ -66,15 +57,16 @@ export function getStaticFilesCollection() {
66
57
  return collection
67
58
  }
68
59
 
60
+
69
61
  export async function dispatchStatic(req, response) {
70
62
  const broker = findStaticBrokerByRoute(req.url)
71
63
 
72
64
  setTimeout(async () => {
73
- if (!broker || broker.should404) { // TESTME
65
+ if (!broker || broker.status === 404) { // TESTME
74
66
  sendNotFound(response)
75
67
  return
76
68
  }
77
- const file = broker.resolvedPath
69
+ const file = join(config.staticDir, broker.route)
78
70
  if (req.headers.range)
79
71
  await sendPartialContent(response, req.headers.range, file)
80
72
  else {
@@ -1,3 +1,5 @@
1
+ import { basename } from 'node:path'
2
+
1
3
  import { cookie } from './cookie.js'
2
4
  import { MockBroker } from './MockBroker.js'
3
5
  import { listFilesRecursively } from './utils/fs.js'
@@ -38,7 +40,7 @@ export function init() {
38
40
  /** @returns {boolean} registered */
39
41
  export function registerMock(file, isFromWatcher = false) {
40
42
  if (findBrokerByFilename(file)?.hasMock(file)
41
- || !isFileAllowed(file)
43
+ || !isFileAllowed(basename(file)) // TESTME
42
44
  || !filenameIsValid(file))
43
45
  return false
44
46