mockaton 8.27.0 → 9.1.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.27.0",
5
+ "version": "9.1.2",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
@@ -19,8 +19,9 @@
19
19
  },
20
20
  "scripts": {
21
21
  "test": "node --test 'src/**/*.test.js'",
22
- "coverage": "node --test --test-reporter=lcov --test-reporter-destination=.coverage/lcov.info --experimental-test-coverage 'src/**/*.test.js'",
23
- "start": "node --watch src/cli.js",
22
+ "coverage": "node --test --test-reporter=lcov --test-reporter-destination=lcov.info --experimental-test-coverage 'src/**/*.test.js'",
23
+ "start": "node src/cli.js",
24
+ "watch": "node --watch src/cli.js",
24
25
  "pixaton": "node --test --import=./pixaton-tests/_setup.js --experimental-test-isolation=none 'pixaton-tests/**/*.test.js'",
25
26
  "outdated": "npm outdated --parseable | awk -F: '{ printf \"npm i %-30s ;# %s\\n\", $4, $2 }'"
26
27
  },
package/src/Api.js CHANGED
@@ -25,15 +25,9 @@ export const apiGetRequests = new Map([
25
25
  '/Logo.svg'
26
26
  ].map(f => [API.dashboard + f, serveDashboardAsset(f)]),
27
27
 
28
- [API.cors, getIsCorsAllowed],
29
- [API.static, listStaticFiles],
30
- [API.mocks, listMockBrokers],
31
- [API.cookies, listCookies],
32
- [API.fallback, getProxyFallback],
33
- [API.comments, listComments],
34
- [API.globalDelay, getGlobalDelay],
28
+ [API.state, getState],
35
29
  [API.syncVersion, longPollClientSyncVersion],
36
- [API.collectProxied, getCollectProxied]
30
+ [API.throws, () => { throw new Error('Test500') }]
37
31
  ])
38
32
 
39
33
  export const apiPatchRequests = new Map([
@@ -55,19 +49,29 @@ export const apiPatchRequests = new Map([
55
49
  /** # GET */
56
50
 
57
51
  function serveDashboardAsset(f) {
58
- return (_, response) => sendFile(response, join(import.meta.dirname, f))
52
+ return (_, response) => {
53
+ if (f.endsWith('.html'))
54
+ response.setHeader('Content-Security-Policy', `default-src 'self'; img-src data: blob: 'self'`)
55
+ return sendFile(response, join(import.meta.dirname, f))
56
+ }
59
57
  }
60
58
 
61
- function listCookies(_, response) { sendJSON(response, cookie.list()) }
62
- function listComments(_, response) { sendJSON(response, mockBrokersCollection.extractAllComments()) }
59
+ function getState(_, response) {
60
+ sendJSON(response, {
61
+ cookies: cookie.list(),
62
+ comments: mockBrokersCollection.extractAllComments(),
63
+
64
+ brokersByMethod: mockBrokersCollection.all(),
65
+ staticBrokers: staticCollection.all(),
63
66
 
64
- function listStaticFiles(_, response) { sendJSON(response, staticCollection.all()) }
65
- function listMockBrokers(_, response) { sendJSON(response, mockBrokersCollection.all()) }
67
+ delay: config.delay,
68
+ delayJitter: config.delayJitter,
66
69
 
67
- function getGlobalDelay(_, response) { sendJSON(response, config.delay) }
68
- function getProxyFallback(_, response) { sendJSON(response, config.proxyFallback) }
69
- function getCollectProxied(_, response) { sendJSON(response, config.collectProxied) }
70
- function getIsCorsAllowed(_, response) { sendJSON(response, config.corsAllowed) }
70
+ proxyFallback: config.proxyFallback,
71
+ collectProxied: config.collectProxied,
72
+ corsAllowed: config.corsAllowed
73
+ })
74
+ }
71
75
 
72
76
  function longPollClientSyncVersion(req, response) {
73
77
  if (uiSyncVersion.version !== Number(req.headers[DF.syncVersion])) {
@@ -8,9 +8,6 @@ export class Commander {
8
8
  this.#addr = addr
9
9
  }
10
10
 
11
- #get(api) {
12
- return fetch(this.#addr + api)
13
- }
14
11
  #patch(api, body) {
15
12
  return fetch(this.#addr + api, {
16
13
  method: 'PATCH',
@@ -18,47 +15,12 @@ export class Commander {
18
15
  })
19
16
  }
20
17
 
21
- /** @type {JsonPromise<ClientBrokersByMethod>} */
22
- listMocks() {
23
- return this.#get(API.mocks)
24
- }
25
-
26
- /** @type {JsonPromise<ClientStaticBrokers>} */
27
- listStaticFiles() {
28
- return this.#get(API.static)
29
- }
30
-
31
- /** @type {JsonPromise<[label:string, selected:boolean][]>} */
32
- listCookies() {
33
- return this.#get(API.cookies)
34
- }
35
-
36
- /** @type {JsonPromise<string[]>} */
37
- listComments() {
38
- return this.#get(API.comments)
39
- }
40
-
41
- /** @type {JsonPromise<string>} */
42
- getProxyFallback() {
43
- return this.#get(API.fallback)
44
- }
45
-
46
- /** @type {JsonPromise<boolean>} */
47
- getCollectProxied() {
48
- return this.#get(API.collectProxied)
49
- }
50
-
51
- /** @type {JsonPromise<boolean>} */
52
- getCorsAllowed() {
53
- return this.#get(API.cors)
54
- }
55
-
56
- /** @type {JsonPromise<number>} */
57
- getGlobalDelay() {
58
- return this.#get(API.globalDelay)
18
+ /** @returns {JsonPromise<State>} */
19
+ getState() {
20
+ return fetch(this.#addr + API.state)
59
21
  }
60
-
61
- /** @type {JsonPromise<number>} */
22
+
23
+ /** @returns {JsonPromise<number>} */
62
24
  getSyncVersion(currentSyncVersion, abortSignal) {
63
25
  return fetch(this.#addr + API.syncVersion, {
64
26
  signal: AbortSignal.any([abortSignal, AbortSignal.timeout(LONG_POLL_SERVER_TIMEOUT + 1000)]),
@@ -3,20 +3,19 @@ export const API = {
3
3
  dashboard: MOUNT,
4
4
  bulkSelect: MOUNT + '/bulk-select-by-comment',
5
5
  collectProxied: MOUNT + '/collect-proxied',
6
- comments: MOUNT + '/comments',
7
6
  cookies: MOUNT + '/cookies',
8
7
  cors: MOUNT + '/cors',
9
8
  delay: MOUNT + '/delay',
10
9
  delayStatic: MOUNT + '/delay-static',
11
10
  fallback: MOUNT + '/fallback',
12
11
  globalDelay: MOUNT + '/global-delay',
13
- mocks: MOUNT + '/mocks',
14
12
  proxied: MOUNT + '/proxied',
15
13
  reset: MOUNT + '/reset',
16
14
  select: MOUNT + '/select',
17
- static: MOUNT + '/static',
15
+ state: MOUNT + '/state',
18
16
  staticStatus: MOUNT + '/static-status',
19
- syncVersion: MOUNT + '/sync_version'
17
+ syncVersion: MOUNT + '/sync-version',
18
+ throws: MOUNT + '/throws',
20
19
  }
21
20
 
22
21
  export const DF = { // Dashboard Fields (XHR)
package/src/Dashboard.css CHANGED
@@ -1,16 +1,16 @@
1
1
  :root {
2
- --radius: 4px;
3
- --boxShadow1: 0 3px 1px -1px rgba(0, 0, 0, 0.04), 0 1px 1px 0 rgba(0, 0, 0, 0.1), 0 1px 3px 0 rgba(0, 0, 0, 0.1);
2
+ --radius: 8px;
3
+ --boxShadow1: rgba(0, 0, 0, 0.18) 0 2px 1px -1px, rgba(0, 0, 0, 0.12) 0 1px 1px 0, rgba(0, 0, 0, 0.1) 0 1px 3px 0px;
4
4
  }
5
5
 
6
6
  @media (prefers-color-scheme: light) {
7
7
  :root {
8
8
  --color4xxBackground: #ffedd1;
9
- --colorAccent: #0068c1;
9
+ --colorAccent: #0b61ec;
10
10
  --colorBackground: #fff;
11
11
  --colorComboBoxHeaderBackground: #fff;
12
12
  --colorComboBoxBackground: #eee;
13
- --colorHeaderBackground: #f0f0f0;
13
+ --colorHeaderBackground: #efefef;
14
14
  --colorSecondaryButtonBackground: #fcfcfc;
15
15
  --colorSecondaryActionBorder: #ddd;
16
16
  --colorSecondaryAction: #666;
@@ -31,7 +31,7 @@
31
31
  color: #9b71e8
32
32
  }
33
33
  .syntaxStr, .syntaxAttrVal {
34
- color: #3e8300
34
+ color: #388E3C
35
35
  }
36
36
  }
37
37
  @media (prefers-color-scheme: dark) {
@@ -94,12 +94,18 @@ body {
94
94
  scrollbar-width: thin;
95
95
  }
96
96
 
97
- select, a, input, button, summary {
98
- &:focus-visible {
97
+ select, a, input, button {
98
+ &:focus {
99
99
  outline: 2px solid var(--colorAccent);
100
100
  }
101
101
  }
102
102
 
103
+ input[type="checkbox"] {
104
+ &:focus {
105
+ outline: 0;
106
+ }
107
+ }
108
+
103
109
  a,
104
110
  button,
105
111
  input[type=checkbox],
@@ -116,7 +122,6 @@ select {
116
122
  font-size: 100%;
117
123
  color: var(--colorText);
118
124
  cursor: pointer;
119
- outline: 0;
120
125
  border-radius: var(--radius);
121
126
  appearance: none;
122
127
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23888888'><path d='M16.59 8.59 12 13.17 7.41 8.59 6 10l6 6 6-6z'/></svg>") no-repeat;
@@ -141,14 +146,14 @@ header {
141
146
  display: flex;
142
147
  width: 100%;
143
148
  padding: 16px;
149
+ border-bottom: 1px solid var(--colorSecondaryActionBorder);
144
150
  background: var(--colorHeaderBackground);
145
- box-shadow: var(--boxShadow1);
146
151
 
147
152
  > div {
148
153
  display: flex;
149
154
  flex-wrap: wrap;
150
155
  align-items: flex-end;
151
- gap: 16px 10px;
156
+ gap: 16px 8px;
152
157
 
153
158
  @media (max-width: 800px) {
154
159
  max-width: 400px;
@@ -189,9 +194,9 @@ header {
189
194
  height: 28px;
190
195
  padding: 4px 8px;
191
196
  border: 0;
197
+ border: 1px solid var(--colorSecondaryActionBorder);
192
198
  border-right: 3px solid transparent;
193
199
  margin-top: 4px;
194
- outline: 1px solid var(--colorSecondaryActionBorder);
195
200
  color: var(--colorText);
196
201
  font-size: 11px;
197
202
  background-color: var(--colorComboBoxHeaderBackground);
@@ -201,7 +206,7 @@ header {
201
206
  select:enabled:hover {
202
207
  background: var(--colorHover);
203
208
  }
204
-
209
+
205
210
  &.GlobalDelayField {
206
211
  width: 84px;
207
212
 
@@ -525,7 +530,7 @@ table {
525
530
  .StaticFilesList {
526
531
  a {
527
532
  display: inline-block;
528
- padding: 8px 0;
533
+ padding: 6px 0;
529
534
  margin-left: 4px;
530
535
  border-radius: var(--radius);
531
536
  color: var(--colorAccent);
@@ -585,8 +590,7 @@ table {
585
590
  }
586
591
 
587
592
  .dittoDir {
588
- opacity: 0.9;
589
- filter: saturate(0);
593
+ opacity: 0.6;
590
594
  }
591
595
 
592
596
  .ErrorToast {
package/src/Dashboard.js CHANGED
@@ -27,7 +27,7 @@ const Strings = {
27
27
  proxy_toggler: 'Proxy Toggler',
28
28
  reset: 'Reset',
29
29
  save_proxied: 'Save Mocks',
30
- static_get: 'Static Folder GET',
30
+ static_get: 'Static GET',
31
31
  title: 'Mockaton'
32
32
  }
33
33
 
@@ -75,56 +75,41 @@ for (const k of Object.keys(CSS))
75
75
  CSS[k] = k
76
76
 
77
77
 
78
+ /** @type {State & {
79
+ * groupByMethod: boolean,
80
+ * canProxy: boolean
81
+ * }} */
78
82
  const state = {
79
- /** @type {ClientBrokersByMethod} */
80
83
  brokersByMethod: {},
81
-
82
- /** @type {ClientStaticBrokers} */
83
84
  staticBrokers: {},
84
-
85
- /** @type {[label:string, selected:boolean][]} */
86
85
  cookies: [],
87
-
88
- /** @type {string[]} */
89
86
  comments: [],
90
-
91
87
  delay: 0,
92
-
93
88
  collectProxied: false,
94
-
95
- fallbackAddress: '',
96
-
89
+ proxyFallback: '',
90
+
97
91
  groupByMethod: true, // TODO read from localstorage
98
92
 
99
93
  get canProxy() {
100
- return Boolean(this.fallbackAddress)
94
+ return Boolean(this.proxyFallback)
101
95
  }
102
96
  }
103
97
 
104
98
  const mockaton = new Commander(window.location.origin)
105
99
  updateState()
106
100
  initLongPoll()
107
- function updateState() {
108
- Promise.all([
109
- mockaton.listMocks(),
110
- mockaton.listStaticFiles(),
111
- mockaton.listCookies(),
112
- mockaton.listComments(),
113
- mockaton.getGlobalDelay(),
114
- mockaton.getCollectProxied(),
115
- mockaton.getProxyFallback()
116
- ].map(api => api.then(response => response.ok && response.json())))
117
- .then(data => {
118
- state.brokersByMethod = data[0]
119
- state.staticBrokers = data[1]
120
- state.cookies = data[2]
121
- state.comments = data[3]
122
- state.delay = data[4]
123
- state.collectProxied = data[5]
124
- state.fallbackAddress = data[6]
125
- document.body.replaceChildren(...App())
126
- })
127
- .catch(onError)
101
+
102
+ async function updateState() {
103
+ try {
104
+ const response = await mockaton.getState()
105
+ if (!response.ok)
106
+ throw response.status
107
+ Object.assign(state, await response.json())
108
+ document.body.replaceChildren(...App())
109
+ }
110
+ catch (error) {
111
+ onError(parseError(error))
112
+ }
128
113
  }
129
114
 
130
115
  const r = createElement
@@ -268,7 +253,7 @@ function GlobalDelayField() {
268
253
 
269
254
 
270
255
  function ProxyFallbackField() {
271
- const { fallbackAddress, collectProxied } = state
256
+ const { proxyFallback, collectProxied } = state
272
257
  function onChange() {
273
258
  const saveCheckbox = this.closest(`.${CSS.FallbackBackend}`).querySelector('[type=checkbox]')
274
259
  saveCheckbox.disabled = !this.validity.valid || !this.value.trim()
@@ -289,12 +274,12 @@ function ProxyFallbackField() {
289
274
  type: 'url',
290
275
  autocomplete: 'none',
291
276
  placeholder: Strings.fallback_server_placeholder,
292
- value: fallbackAddress,
277
+ value: proxyFallback,
293
278
  onChange
294
279
  })),
295
280
  r(SaveProxiedCheckbox, {
296
281
  collectProxied,
297
- disabled: !fallbackAddress
282
+ disabled: !proxyFallback
298
283
  })))
299
284
  }
300
285
 
@@ -337,6 +322,8 @@ function ResetButton() {
337
322
 
338
323
  function MockList() {
339
324
  const { brokersByMethod, groupByMethod } = state
325
+ const canProxy = state.canProxy
326
+
340
327
  if (!Object.keys(brokersByMethod).length)
341
328
  return (
342
329
  r('div', className(CSS.empty),
@@ -345,49 +332,19 @@ function MockList() {
345
332
  if (groupByMethod)
346
333
  return (
347
334
  r('div', null,
348
- r('table', null, Object.entries(brokersByMethod).map(([method, brokers]) =>
349
- r(RowsByMethod, { method, brokers })))))
335
+ r('table', null, Object.keys(brokersByMethod).map(method =>
336
+ r('tbody', null,
337
+ r('tr', null,
338
+ r('th', { colspan: 2 + Number(canProxy) }),
339
+ r('th', null, method)),
340
+ rowsFor(method).map(Row))))))
350
341
 
351
342
  return (
352
343
  r('div', null,
353
344
  r('table', null,
354
- r(RowsUngrouped))))
345
+ r('tbody', null, rowsFor('*').map(Row)))))
355
346
  }
356
347
 
357
- function RowsByMethod({ method, brokers }) {
358
- const canProxy = state.canProxy
359
- const rawRows = Object.entries(brokers).map(([urlMask, broker]) => [urlMask, broker, method])
360
- return (
361
- r('tbody', null,
362
- r('tr', null,
363
- r('th', { colspan: 2 + Number(canProxy) }),
364
- r('th', null, method)),
365
- Rows(rawRows)))
366
- }
367
-
368
- function RowsUngrouped() {
369
- const { brokersByMethod } = state
370
- const rawRows = []
371
- for (const [method, brokers] of Object.entries(brokersByMethod))
372
- for (const [urlMask, broker] of Object.entries(brokers))
373
- rawRows.push([urlMask, broker, method])
374
-
375
- return r('tbody', null, Rows(rawRows))
376
- }
377
-
378
- function Rows(rawRows) {
379
- const sorted = rawRows
380
- .filter(([, broker]) => broker.mocks.length > 1) // >1 because of autogen500
381
- .sort(([aUrl], [bUrl]) => aUrl.localeCompare(bUrl))
382
- const urlMasksDittoed = dittoSplitPaths(sorted.map(([urlMask]) => urlMask))
383
- return sorted.map(([urlMask, broker, method], i) =>
384
- r(Row, {
385
- broker,
386
- method,
387
- urlMask,
388
- urlMaskDittoed: urlMasksDittoed[i]
389
- }))
390
- }
391
348
 
392
349
  function Row({ method, urlMask, urlMaskDittoed, broker }) {
393
350
  const canProxy = state.canProxy
@@ -397,8 +354,27 @@ function Row({ method, urlMask, urlMaskDittoed, broker }) {
397
354
  r('td', null, r(DelayRouteToggler, { broker })),
398
355
  r('td', null, r(InternalServerErrorToggler, { broker })),
399
356
  r('td', null, r(PreviewLink, { method, urlMask, urlMaskDittoed })),
400
- r('td', null, r(MockSelector, { broker }))
401
- ))
357
+ r('td', null, r(MockSelector, { broker }))))
358
+ }
359
+
360
+ function rowsFor(targetMethod) {
361
+ const { brokersByMethod } = state
362
+
363
+ const rows = []
364
+ for (const [method, brokers] of Object.entries(brokersByMethod))
365
+ if (targetMethod === '*' || targetMethod === method)
366
+ for (const [urlMask, broker] of Object.entries(brokers))
367
+ rows.push({ method, urlMask, broker })
368
+
369
+ const sorted = rows
370
+ .filter((r) => r.broker.mocks.length > 1) // >1 because of autogen500
371
+ .sort((rA, rB) => rA.urlMask.localeCompare(rB.urlMask))
372
+
373
+ const urlMasksDittoed = dittoSplitPaths(sorted.map(r => r.urlMask))
374
+ return sorted.map((r, i) => ({
375
+ ...r,
376
+ urlMaskDittoed: urlMasksDittoed[i]
377
+ }))
402
378
  }
403
379
 
404
380
  function PreviewLink({ method, urlMask, urlMaskDittoed }) {
@@ -746,6 +722,8 @@ async function parseError(response) {
746
722
  }
747
723
 
748
724
  function onError(error) {
725
+ if (error?.name === 'AbortError')
726
+ return
749
727
  if (error?.message === 'Failed to fetch')
750
728
  showErrorToast('Looks like the Mockaton server is not running')
751
729
  else
package/src/Logo.svg CHANGED
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <svg width="556" height="100" version="1.1" viewBox="0 0 556 100" xmlns="http://www.w3.org/2000/svg">
3
3
  <style>:root { --color: #000000; }
4
- @media (prefers-color-scheme: light) { :root { --color: #444 } }
4
+ @media (prefers-color-scheme: light) { :root { --color: #333 } }
5
5
  @media (prefers-color-scheme: dark) { :root { --color: #eee } }
6
6
  path { fill: var(--color) }
7
7
  </style>
@@ -10,7 +10,7 @@
10
10
  d="m13.75 1.8789c-5.9487 0.19352-10.865 4.5652-11.082 11.686v81.445c-1e-7 2.216 1.784 4 4 4h4.793c2.216 0 4-1.784 4-4v-64.982c0.02794-3.4488 3.0988-3.5551 4.2031-1.1562l16.615 59.059c1.4393 5.3711 5.1083 7.9633 8.7656 7.9473 3.6573 0.01603 7.3263-2.5762 8.7656-7.9473l16.615-59.059c1.1043-2.3989 4.1752-2.2925 4.2031 1.1562v64.982c0 2.216 1.784 4 4 4h4.793c2.216 0 4-1.784 4-4v-81.445c-0.17732-7.0807-5.1334-11.492-11.082-11.686-5.9487-0.19352-12.652 3.8309-15.609 13.619l-15.686 57.334-15.686-57.334c-2.9569-9.7882-9.6607-13.813-15.609-13.619zm239.19 0.074219c-2.216 0-4 1.784-4 4v89.057c0 2.216 1.784 4 4 4h4.793c2.216 0 3.9868-1.784 4-4l0.10644-17.94c0.0734-0.07237 12.175-13.75 12.175-13.75 5.6772 11.091 11.404 22.158 17.113 33.232 1.0168 1.9689 3.4217 2.7356 5.3906 1.7188l4.2578-2.1992c1.9689-1.0168 2.7356-3.4217 1.7188-5.3906-6.4691-12.585-12.958-25.16-19.442-37.738l17.223-19.771c1.4555-1.671 1.2803-4.189-0.39062-5.6445l-3.6133-3.1465c-0.73105-0.63679-1.6224-0.96212-2.5176-0.98633-1.151-0.03113-2.3063 0.43508-3.125 1.375l-28.896 33.174v-51.99c0-2.216-1.784-4-4-4zm-58.255 23.316c-10.699 0-19.312 8.6137-19.312 19.312v34.535c0 10.699 8.6137 19.312 19.312 19.312h19.717c10.699 0 19.311-8.6137 19.311-19.312l-0.125-7.8457c0-2.216-1.784-4-4-4h-4.6524c-2.216 0-4 1.784-4 4l3e-3 6.7888c3e-3 3.8063-1.5601 9.3694-8.4716 9.3694h-15.846c-6.9115 0-8.4766-5.5631-8.4766-12.475v-26.209c0-6.9115 1.5651-12.477 8.4766-12.477h15.846c6.6937 0 8.3697 5.2207 8.4687 11.828v2.2207c0 2.216 1.784 4 4 4h4.6524c2.216 0 4-1.784 4-4l0.125-5.7363c0-10.699-8.6117-19.312-19.311-19.312zm-72.182 0c-10.699 0-19.312 8.6137-19.312 19.312v34.535c0 10.699 8.6137 19.312 19.312 19.312h19.717c10.699 0 19.311-8.6137 19.311-19.312v-34.535c0-10.699-8.6117-19.312-19.311-19.312zm1.9356 11h15.846c6.9115 0 8.4746 5.5651 8.4746 12.477v26.209c0 6.9115-1.5631 12.475-8.4746 12.475h-15.846c-6.9115 0-8.4766-5.5631-8.4766-12.475v-26.209c0-6.9115 1.5651-12.477 8.4766-12.477z"/>
11
11
  <path
12
12
  d="m331.9 25.27c-10.699 0-19.312 8.6137-19.312 19.312v4.3682c0 2.216 1.784 4 4 4h4.7715c2.216 0 4-1.784 4-4v-0.20414c0-6.9115 1.5651-12.477 8.4766-12.477h15.846c6.9115 0 8.4746 5.5651 8.4746 12.477v7.0148h-28.059c-10.699 0-19.312 8.6117-19.312 19.311v4.0477c0 10.699 8.6137 19.313 19.312 19.312h17.812c2.216-1e-6 4-1.784 4-4v-4.7715c0-2.216-1.784-4-4-4h-13.648c-6.9115-2e-5 -12.477-1.5651-12.477-8.5649 0-6.9998 5.5651-8.5629 12.477-8.5629h23.895v25.897c0 2.216 1.784 4 4 4h4.7715c2.216-1e-6 4-1.784 4-4v-49.848c0-10.699-8.6117-19.312-19.311-19.312z"
13
- opacity="0.8"/>
13
+ opacity="0.75"/>
14
14
  <path
15
15
  d="m392.75 1.373c-2.216 0-4 1.784-4 4v18.043h-5.3086c-2.216 0-4 1.784-4 4v4.793c0 2.216 1.784 4 4 4h5.3086v51.398c0 6.1465 3.7064 10.823 9.232 10.823h16.531c2.216 0 4-1.784 4-4v-4.793c0-2.216-1.784-4-4-4h-12.97v-49.428h9.8711c2.216 0 4-1.784 4-4v-4.793c0-2.216-1.784-4-4-4h-9.8711v-18.043c0-2.216-1.784-4-4-4zm122.96 23.896c-10.699 0-19.312 8.6137-19.312 19.312v49.812c0 2.216 1.784 4 4 4h4.7715c2.216 0 4-1.784 4-4v-45.648c0-6.9115 1.5651-12.477 8.4766-12.477h15.846c6.9115 0 8.4746 5.5651 8.4746 12.477v45.684c0 2.216 1.784 4 4 4h4.7715c2.216-1e-6 4-1.784 4-4v-49.848c0-10.699-8.6117-19.312-19.311-19.312zm-69.999 0c-10.699 0-19.312 8.6137-19.312 19.312v34.535c0 10.699 8.6137 19.312 19.312 19.312h19.717c10.699 0 19.311-8.6137 19.311-19.312v-34.535c0-10.699-8.6117-19.312-19.311-19.312zm1.9356 11h15.846c6.9115 0 8.4746 5.5651 8.4746 12.477v26.209c0 6.9115-1.5631 12.475-8.4746 12.475h-15.846c-6.9115 0-8.4766-5.5631-8.4766-12.475v-26.209c0-6.9115 1.5651-12.477 8.4766-12.477z"/>
16
16
  </g>
package/src/Mockaton.js CHANGED
@@ -14,15 +14,8 @@ import { apiPatchRequests, apiGetRequests } from './Api.js'
14
14
  import { sendNoContent, sendInternalServerError, sendUnprocessableContent } from './utils/http-response.js'
15
15
 
16
16
 
17
- process.on('unhandledRejection', error => { throw error })
18
-
19
17
  export function Mockaton(options) {
20
- const error = setup(options)
21
- if (error) {
22
- log.error(error)
23
- process.exitCode = 1
24
- return
25
- }
18
+ setup(options)
26
19
 
27
20
  mockBrokerCollection.init()
28
21
  staticCollection.init()
@@ -31,12 +24,7 @@ export function Mockaton(options) {
31
24
 
32
25
  const server = createServer(onRequest)
33
26
 
34
- server.listen(config.port, config.host, function (error) {
35
- if (error) {
36
- log.error(error)
37
- process.exit(1)
38
- return
39
- }
27
+ server.listen(config.port, config.host, function () {
40
28
  const { address, port } = this.address()
41
29
  const url = `http://${address}:${port}`
42
30
  log.info('Listening', url)
@@ -44,11 +32,6 @@ export function Mockaton(options) {
44
32
  config.onReady(url + API.dashboard)
45
33
  })
46
34
 
47
- server.on('error', error => {
48
- log.error(error.message)
49
- process.exit(1)
50
- })
51
-
52
35
  return server
53
36
  }
54
37
 
package/src/cli.js CHANGED
@@ -8,26 +8,35 @@ import { Mockaton } from '../index.js'
8
8
  import pkgJSON from '../package.json' with { type: 'json' }
9
9
 
10
10
 
11
- const args = parseArgs({
12
- options: {
13
- config: { short: 'c', type: 'string' },
11
+ process.on('unhandledRejection', error => { throw error })
14
12
 
15
- port: { short: 'p', type: 'string' },
16
- host: { short: 'H', type: 'string' },
13
+ let args
14
+ try {
15
+ args = parseArgs({
16
+ options: {
17
+ config: { short: 'c', type: 'string' },
17
18
 
18
- 'mocks-dir': { short: 'm', type: 'string' },
19
- 'static-dir': { short: 's', type: 'string' },
19
+ port: { short: 'p', type: 'string' },
20
+ host: { short: 'H', type: 'string' },
20
21
 
21
- help: { short: 'h', type: 'boolean' },
22
- version: { short: 'v', type: 'boolean' },
22
+ 'mocks-dir': { short: 'm', type: 'string' },
23
+ 'static-dir': { short: 's', type: 'string' },
23
24
 
24
- quiet: { short: 'q', type: 'boolean' },
25
- debug: { type: 'boolean' }
26
- }
27
- }).values
25
+ quiet: { short: 'q', type: 'boolean' },
26
+ 'no-open': { short: 'n', type: 'boolean' },
27
+
28
+ help: { short: 'h', type: 'boolean' },
29
+ version: { short: 'v', type: 'boolean' }
30
+ }
31
+ }).values
32
+ }
33
+ catch (error) {
34
+ console.error(error.message)
35
+ process.exit(1)
36
+ }
28
37
 
29
38
 
30
- if (args.version)
39
+ if (args.version)
31
40
  console.log(pkgJSON.version)
32
41
 
33
42
  else if (args.help)
@@ -44,6 +53,8 @@ Options:
44
53
  -p, --port <port> (default: 0) which means auto-assigned
45
54
 
46
55
  -q, --quiet Errors only
56
+ --no-open Don’t open dashboard in a browser (noops onReady callback)
57
+
47
58
  -h, --help Show this help
48
59
  -v, --version Show version
49
60
 
@@ -69,6 +80,16 @@ else {
69
80
  if (args['static-dir']) opts.staticDir = args['static-dir']
70
81
 
71
82
  if (args.quiet) opts.logLevel = 'quiet'
83
+ if (args['no-open']) opts.onReady = () => {}
72
84
 
73
- Mockaton(opts)
85
+ try {
86
+ Mockaton(opts).on('error', error => {
87
+ console.error(error.message)
88
+ process.exit(1)
89
+ })
90
+ }
91
+ catch (err) {
92
+ console.error(err?.message || err)
93
+ process.exit(1)
94
+ }
74
95
  }