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 +1 -1
- package/src/Api.js +16 -16
- package/src/ApiConstants.js +2 -2
- package/src/Commander.js +3 -3
- package/src/Dashboard.js +23 -20
- package/src/MockBroker.js +2 -2
- package/src/Mockaton.js +1 -1
- package/src/StaticDispatcher.js +22 -30
- package/src/mockBrokersCollection.js +3 -1
package/package.json
CHANGED
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 => [
|
|
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.
|
|
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(
|
|
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.
|
|
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.
|
|
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
|
|
201
|
+
async function setStaticRouteStatusCode(req, response) {
|
|
202
202
|
const body = await parseJSON(req)
|
|
203
|
-
const
|
|
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 (
|
|
209
|
-
sendUnprocessableContent(response, `Expected a
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
227
|
+
broker.setDelayed(delayed)
|
|
228
228
|
sendOK(response)
|
|
229
229
|
}
|
|
230
230
|
}
|
package/src/ApiConstants.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
48
|
-
return this.#patch(API.
|
|
47
|
+
setStaticRouteStatus(routeUrlMask, status) {
|
|
48
|
+
return this.#patch(API.staticStatus, {
|
|
49
49
|
[DF.routeUrlMask]: routeUrlMask,
|
|
50
|
-
[DF.
|
|
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
|
|
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,
|
|
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, {
|
|
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
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
|
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(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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,
|
|
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
|
-
|
|
86
|
+
setDelayed(delayed) {
|
|
87
87
|
this.currentMock.delayed = delayed
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
|
|
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(
|
|
57
|
+
else if (method === 'GET' && findStaticBrokerByRoute(url))
|
|
58
58
|
await dispatchStatic(req, response)
|
|
59
59
|
|
|
60
60
|
else
|
package/src/StaticDispatcher.js
CHANGED
|
@@ -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(
|
|
12
|
-
this.
|
|
11
|
+
constructor(route) {
|
|
12
|
+
this.route = route
|
|
13
13
|
this.delayed = false
|
|
14
|
-
this.
|
|
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
|
-
|
|
31
|
-
|
|
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(
|
|
46
|
-
if (!isFileAllowed(basename(
|
|
33
|
+
export function registerStaticMock(relativeFile) {
|
|
34
|
+
if (!isFileAllowed(basename(relativeFile)))
|
|
47
35
|
return false
|
|
48
36
|
|
|
49
|
-
|
|
50
|
-
if (findStaticBrokerByRoute(
|
|
37
|
+
const route = '/' + relativeFile
|
|
38
|
+
if (findStaticBrokerByRoute(route))
|
|
51
39
|
return false
|
|
52
40
|
|
|
53
|
-
collection[
|
|
41
|
+
collection[route] = new StaticBroker(route)
|
|
54
42
|
return true
|
|
55
43
|
}
|
|
56
44
|
|
|
57
|
-
|
|
58
|
-
|
|
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.
|
|
65
|
+
if (!broker || broker.status === 404) { // TESTME
|
|
74
66
|
sendNotFound(response)
|
|
75
67
|
return
|
|
76
68
|
}
|
|
77
|
-
const file = broker.
|
|
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
|
|