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/CHANGELOG.md +6 -0
- package/README.md +79 -22
- package/index.d.ts +23 -10
- package/index.js +0 -1
- package/lcov.info +2572 -0
- package/package.json +4 -3
- package/src/Api.js +21 -17
- package/src/ApiCommander.js +5 -43
- package/src/ApiConstants.js +3 -4
- package/src/Dashboard.css +19 -15
- package/src/Dashboard.js +55 -77
- package/src/Logo.svg +2 -2
- package/src/Mockaton.js +2 -19
- package/src/cli.js +36 -15
- package/src/config.js +14 -21
- package/src/utils/http-response.js +1 -1
- package/src/utils/mime.js +26 -13
- package/mockup.svg +0 -1037
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "mockaton",
|
|
3
3
|
"description": "HTTP Mock Server",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "
|
|
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
|
|
23
|
-
"start": "node
|
|
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.
|
|
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.
|
|
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) =>
|
|
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
|
|
62
|
-
|
|
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
|
-
|
|
65
|
-
|
|
67
|
+
delay: config.delay,
|
|
68
|
+
delayJitter: config.delayJitter,
|
|
66
69
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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])) {
|
package/src/ApiCommander.js
CHANGED
|
@@ -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
|
-
/** @
|
|
22
|
-
|
|
23
|
-
return this.#
|
|
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
|
-
/** @
|
|
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)]),
|
package/src/ApiConstants.js
CHANGED
|
@@ -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
|
-
|
|
15
|
+
state: MOUNT + '/state',
|
|
18
16
|
staticStatus: MOUNT + '/static-status',
|
|
19
|
-
syncVersion: MOUNT + '/
|
|
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:
|
|
3
|
-
--boxShadow1:
|
|
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: #
|
|
9
|
+
--colorAccent: #0b61ec;
|
|
10
10
|
--colorBackground: #fff;
|
|
11
11
|
--colorComboBoxHeaderBackground: #fff;
|
|
12
12
|
--colorComboBoxBackground: #eee;
|
|
13
|
-
--colorHeaderBackground: #
|
|
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: #
|
|
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
|
|
98
|
-
&:focus
|
|
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
|
|
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:
|
|
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.
|
|
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
|
|
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
|
-
|
|
96
|
-
|
|
89
|
+
proxyFallback: '',
|
|
90
|
+
|
|
97
91
|
groupByMethod: true, // TODO read from localstorage
|
|
98
92
|
|
|
99
93
|
get canProxy() {
|
|
100
|
-
return Boolean(this.
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
mockaton.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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 {
|
|
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:
|
|
277
|
+
value: proxyFallback,
|
|
293
278
|
onChange
|
|
294
279
|
})),
|
|
295
280
|
r(SaveProxiedCheckbox, {
|
|
296
281
|
collectProxied,
|
|
297
|
-
disabled: !
|
|
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.
|
|
349
|
-
r(
|
|
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(
|
|
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: #
|
|
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.
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
12
|
-
options: {
|
|
13
|
-
config: { short: 'c', type: 'string' },
|
|
11
|
+
process.on('unhandledRejection', error => { throw error })
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
let args
|
|
14
|
+
try {
|
|
15
|
+
args = parseArgs({
|
|
16
|
+
options: {
|
|
17
|
+
config: { short: 'c', type: 'string' },
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
port: { short: 'p', type: 'string' },
|
|
20
|
+
host: { short: 'H', type: 'string' },
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
'mocks-dir': { short: 'm', type: 'string' },
|
|
23
|
+
'static-dir': { short: 's', type: 'string' },
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
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
|
-
|
|
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
|
}
|